perm filename CLCOMP.MSG[COM,LSP]5 blob
sn#858259 filedate 1988-06-10 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00002 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002
C00003 ENDMK
C⊗;
∂29-Mar-88 2234 CL-Compiler-mailer Eval-When -- a radical view
Received: from labrea.Stanford.EDU by SAIL.Stanford.EDU with TCP; 29 Mar 88 22:34:24 PST
Received: by labrea.Stanford.EDU; Tue, 29 Mar 88 22:32:17 PST
Received: from bhopal.lucid.com by edsel id AA12080g; Tue, 29 Mar 88 22:24:31 PST
Received: by bhopal id AA01977g; Tue, 29 Mar 88 22:24:41 PST
Date: Tue, 29 Mar 88 22:24:41 PST
From: Jon L White <edsel!jonl@labrea.Stanford.EDU>
Message-Id: <8803300624.AA01977@bhopal.lucid.com>
To: Rob.MacLachlan@wb1.cs.cmu.edu
Cc: sandra@cs.utah.edu, cl-compiler@sail.stanford.edu
In-Reply-To: Rob.MacLachlan@WB1.CS.CMU.EDU's message of Sat, 26 Mar 88 12:38:29 EST <8803270744.AA29754@edsel.lucid.com>
Subject: Eval-When -- a radical view
You sure put "a mouthful" in your reply! I'm not sure that I'll be able now
to comment on all the things you've brought up, but here goes ...
re: A narrow complaint that I have is that it seems you haven't been as
consistent as you could be in extending the semantics described in CLTL.
In your version, compiling:
(eval-when (compile)
(eval-when (load)
(print 'foo)))
. . .
You're quite right; the code I suggested for EVAL-WHEN should have the line:
(:eval-before-compile T)
changed to be
(:eval-before-compile (or (memq 'eval situations)
(memq 'load situations)))
That should better reflect the semantics of what CLtL calls "compile-time-too".
re: It should also be clear that using a dynamic variable *EVAL-WHEN-STATE* is
an implementation detail, and not part of the inherent semantics. For one,
requiring EVAL to bind a special prevents it from being tail-recursive.
What you really want to do is lexically modify the evaluation rules. Using
a dynamic variable bound by EVAL and COMPILE is an approximation of this,
but things become more confusing when there are any other ways for the
lexical environment to become null.
Right again. Mostly my use of the dynamic variable *EVAL-WHEN-STATE* is
merely to make it easier to understand a rather simple defmacro definition
for EVAL-WHEN.
re: Even supposing we could clearly define EVAL-WHEN in a way that extended
cleanly across all implementations that we want to support, EVAL-WHEN
would still be bad because it is too powerful: it allows users to say
things that aren't meaningful across all implementations -- it encourages
writing of programs that don't work interpreted (or compiled).
This paragraph is representative of large section of your note, basically
saying that trying to "patch up" EVAL-WHEN is a doomed process. I disagree
mildly. In particular, the ability to "say things that aren't meaningful"
is not focused enough to warrant tossing out eval-when. I agree that the
willy-nilly generation of legal syntatic forms will come up with some
meaningless phrases; why, even my proposal presented an interpretation for
(defun foo (x)
(mumble (eval-when (load) (bletch x))))
even though that is clearly a meaningless thing to do. [my presentation was
to view the 'load' situation as meaning that this should be incorporated
into the compiled code and only into the compiled code; Sandra's presentation
-- at least verbally at the Friday morning meetings -- was that it could
mean something like #, and in a way I prefer hers now] Rather, I like the
simplicity of EVAL-WHEN for the combinations that do make good sense. As
you say,
I searched through our system sources looking for all uses of EVAL-WHEN.
Nearly all uses involved one of two situations lists:
(COMPILE LOAD EVAL)
(COMPILE EVAL)
. . .
There were also quite a few uses of the (COMPILE) situation list, but
nearly all of these were erroneous; the code wouldn't have worked
interpreted.
On the other hand, in our system, the relatively few instances of the (COMPILE)
situation are precisely for code that can't work interpreted. I myself have
even inserted a couple of lines like
(eval-when (eval)
(error "You Loser! this file can't be run interpretively"))
We have a few places in our system that are defined only by the code-generator
parts of the compiler; some of these functions have interpreter entries that
look like the classic:
(defun car (x)
(check-type x list)
(car x))
but most are merely internal compiler stuff that doesn't need such an entry.
Files that reference such functions simply can't be run except when compiled.
But the whole point is that whether the number of "meaningful" situations
is 3 or 4 or 5 out of a possible 8, that is no reason to give up just
because the other few are not particularly useful.
Now, Sandra brings up another good point (which you too, Rob, mention) --
The problem of having the same piece of code sometimes get evaluated in
the current lexical environment and sometimes not is going to be easy to
resolve. There does not seem to be much disagreement that the COMPILE
situation must do its evaluation in the null lexical environment. . . .
Maybe I'll exercise my perogative to bring in some "disagreement". Perhaps
feeding an &environment argument to eval-when isn't so bad after all. In
terms of my trial-baloon defmacro for eval-when, the only problematical point
is how to transmit an outter environment down through the code:
(mapc #'eval-internal code)
I'm sure that some suitable solution could be found. Maybe even binding
the *EVAL-WHEN-STATE* to it instead of :EVAL-BEFORE-COMPILE could work?
Also Sandra's mention of a possible definition of DEFMACRO in terms of
EVAL-WHEN and SETF(MACRO-FUNCTION ...) adds weight to the need for a solution.
At any rate, I think this is indeed an important enough problem to spend
some time thinking about [looking for a consistent solution that is, not
just looking for reasons to chuck out the whole kit-and-kaboodle].
If we were to adopt some notion that each "file" is a lexical entity --
equivalent for scoping as if there were a giant (locally ....) enclosing the
entire file -- then it would be even more important to pass in &environment
information to eval-when. [But of course you couldn't do this "enclosing"
literally since that would mean reading in all the forms of the file before
processing any of them]. My proposal for a lexical-file-proclaim needs
such a notion of lexical scoping, and I believe it accurately reflects
desiderata set out by Beckerele and others about the semantics of what
a "file" is such that you can apply COMPILE-FILE to it; but this is a
topic for yet another time.
Incidentally, the example that Sandra offers
(eval-when (eval compile load)
(let ((x (compute-some-value)))
(defmacro foo (y)
`(+ ,x ,y))))
Could just as well have been
(eval-when (eval compile)
(let ((x (compute-some-value)))
(defmacro foo (y)
`(+ ,x ,y))))
That is, the proponents of this style frequently need it only in the
compiler's environment. For an implementation that doesn't have an
interpreter, then the situation marker (eval compile) is still right,
since it means first compiling
(let ((x (compute-some-value)))
(defmacro foo (y)
`(+ ,x ,y)))
and then immediately afterwards calling that compiled "thunk" to be executed.
The macro is now "alive" for subsequent compilations of forms found later in
the file.
-- JonL --
∂29-Mar-88 2236 CL-Compiler-mailer Eval-When -- a radical view
Received: from labrea.Stanford.EDU by SAIL.Stanford.EDU with TCP; 29 Mar 88 22:36:03 PST
Received: by labrea.Stanford.EDU; Tue, 29 Mar 88 22:34:23 PST
Received: from bhopal.lucid.com by edsel id AA12136g; Tue, 29 Mar 88 22:31:34 PST
Received: by bhopal id AA01993g; Tue, 29 Mar 88 22:31:44 PST
Date: Tue, 29 Mar 88 22:31:44 PST
From: Jon L White <edsel!jonl@labrea.Stanford.EDU>
Message-Id: <8803300631.AA01993@bhopal.lucid.com>
To: jeff%aiva.edinburgh.ac.uk@nss.cs.ucl.ac.uk
Cc: cl-compiler@sail.stanford.edu, <@edsel,@labrea.stanford.edu:jonl>
In-Reply-To: Jeff Dalton's message of Mon, 28 Mar 88 17:00:29 bst <22121.8803281600@aiva.ed.ac.uk>
Subject: Eval-When -- a radical view
re: There is one subtlety that I think should be addressed, and that is:
what should implementations that always and only compile do? . . .
So maybe the top-level processor that is masquarading as "top-level EVAL"
should call a private entry into the compiler that doesn't rebind
*EVAL-WHEN-STATE*? I already had to presume such an entry to the
interpreter in the trial-balloon defmacro for EVAL-WHEN.
Even in the most minimal of implementations, I presume that LOAD differs
from COMPILE-FILE in that LOAD will successively "execute" each form
before even reading the next one. And COMPILE-FILE is called primarily
for the side-effect of creating a "binary" file. So it still makes sense
to me to have separate "situation" markers for :EVALUATING and :COMPILING,
even though serious portability questions arise about some combinations
of "situations".
-- JonL --
∂30-Mar-88 1055 CL-Compiler-mailer Eval-When -- a radical view
Received: from XX.LCS.MIT.EDU by SAIL.Stanford.EDU with TCP; 30 Mar 88 10:53:00 PST
Received: from LIVE-OAK.LCS.MIT.EDU by XX.LCS.MIT.EDU via Chaosnet; 30 Mar 88 11:00-EST
Received: from ACORN.Gold-Hill.DialNet.Symbolics.COM by MIT-LIVE-OAK.DialNet.Symbolics.COM via DIAL with SMTP id 85774; 30 Mar 88 10:11:55-EST
Received: from BOSTON.Gold-Hill.DialNet.Symbolics.COM by ACORN.Gold-Hill.DialNet.Symbolics.COM via CHAOS with CHAOS-MAIL id 97736; Wed 30-Mar-88 09:13:24-EST
Date: Wed, 30 Mar 88 09:15 est
From: mike%acorn@oak.lcs.mit.edu (mike@gold-hill.com after 1-April-88)
COMMENTS: NOTE %acorn@oak... CHANGES TO @GOLD-HILL.COM ON 1-April-88
To: edsel!jonl@labrea.Stanford.EDU
Subject: Eval-When -- a radical view
Cc: Rob.MacLachlan@wb1.cs.cmu.edu, sandra@cs.utah.edu,
cl-compiler@sail.stanford.edu
I searched through our system sources looking for all uses of
EVAL-WHEN.
Nearly all uses involved one of two situations lists:
(COMPILE LOAD EVAL)
(COMPILE EVAL)
In our implementation, the most common situation for eval-when is
(compile eval). This is used to exclude macros, constants, etc that
are compiled in to a delivered system. Another common one is
(load eval), which is used within expansions of macros to force loading
of runtime support: e.g.,
(defmacro mac (....)
`(progn
(eval-when (load eval) (require "runtime-support"))
...rest of expansion here....))
This is nice because in the file header you only have to require the
module that defines the macros, via:
(eval-when (compile eval) (require "the-macros")) You don't have to
know where the runtime support lives, or use autoloading or anything.
There are almost no uses of (compile eval load) anywhere.
I am of the opinion that we should define what EVAL-WHEN does, and
not chuck it out in favor of new constructs, like EVAL-EARLY, etc.
...mike beckerle
∂12-Apr-88 1347 CL-Compiler-mailer archives
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 12 Apr 88 13:47:25 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA26559; Tue, 12 Apr 88 14:47:52 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8804122047.AA26559@cs.utah.edu>
Date: Tue, 12 Apr 88 14:47:49 MDT
Subject: archives
To: cl-compiler@sail.stanford.edu
Mail sent to cl-compiler is now being archived on cs.utah.edu, in the
file /v/tmp/spool/mail/cl-compiler. If this file grows too humungous
I'll try to split it up into smaller pieces from time to time.
-Sandra
-------
∂06-May-88 1358 CL-Compiler-mailer nesting of EVAL-WHENs
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 6 May 88 13:58:06 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA26103; Fri, 6 May 88 14:58:39 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805062058.AA26103@cs.utah.edu>
Date: Fri, 6 May 88 14:58:37 MDT
Subject: nesting of EVAL-WHENs
To: cl-compiler@sail.stanford.edu
I've been trying to write up some formal proposals to firm up what we
now seem to think is the "right" way to handle defining macros and
eval-when, and I've run into a problem with the semantics of nested
EVAL-WHENs.
From our Palo Alto meeting, there seemed to be some consensus that the
following kind of code should "work":
(eval-when (eval compile load)
(let ((x (some-hairy-computation)))
(defmacro foo (y)
`(+ ,x ,y))))
Namely, the macro function FOO should be closed over X, and since the value
of X is available at compile time everything should be hunky-dory.
According to our model of how the compiler treats top-level forms,
the defmacro itself expands into another eval-when, something like
(eval-when (eval compile load)
(let ((x (some-hairy-computation)))
(eval-when (eval compile load)
(setf (macro-function 'foo)
#'(lambda (form env)
(let ((y (second form)))
`(+ ,x ,y))))
'foo)))
So, here's the problem. As I understand our latest spec on how
EVAL-WHEN works, the compiler will first evaluate the entire LET form
that binds X in the null lexical environment, and FOO will get the
"right" macro definition as a function closed over X. Then, the
compiler will do the processing for the LOAD part of the EVAL-WHEN. In
doing so, it will hit that nested EVAL-WHEN, see that COMPILE is
specified among the situations, and promptly redefine the macro
definition of FOO as a function in the null lexical environment which
is not closed over X. Which isn't what we wanted to happen.
I thought of maybe saying that LOAD or EVAL processing of the body of
the EVAL-WHEN disables COMPILE processing of nested EVAL-WHENs in
the body. This would be incompatible with the current behavior as
specified in CLtL, however, and I'm not sure that it would be generally
the right thing to do in other situations. Alternatively, we could keep
the current restriction on macro functions always being defined in the
null lexical environment, but that would be difficult to explain using
our model of how defining macros work.
Anybody else have thoughts on this?
-Sandra
-------
∂07-May-88 0456 CL-Compiler-mailer nesting of EVAL-WHENs
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 7 May 88 04:55:55 PDT
Received: by labrea.stanford.edu; Sat, 7 May 88 04:56:02 PDT
Received: from bhopal.lucid.com by edsel id AA13890g; Sat, 7 May 88 02:13:52 PDT
Received: by bhopal id AA05540g; Sat, 7 May 88 02:16:36 PDT
Date: Sat, 7 May 88 02:16:36 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805070916.AA05540@bhopal.lucid.com>
To: sandra@cs.utah.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Sandra J Loosemore's message of Fri, 6 May 88 14:58:37 MDT <8805062058.AA26103@cs.utah.edu>
Subject: nesting of EVAL-WHENs
I'm going to need some more time to think about this question, but vaguely
I thought the model of eval-when processing tried to make sure that subforms
only got evaluated once when there were multiple applicable situations.
For the interior eval-when(eval compile load), the first evaluation during
compilation is because of the EVAL situation in the outter eval-when; then
the second "potential" evaluation is during the compilation of the inner
eval-when, when it notices that it has the 'compile' situaiton. Clearly
we need to insure that the eval-when model has a state that says:
"compiling, but have already eval'd this"
-- JonL --
∂08-May-88 1246 CL-Compiler-mailer Re: nesting of EVAL-WHENs
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 8 May 88 12:45:57 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA03719; Sun, 8 May 88 12:37:57 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805081837.AA03719@cs.utah.edu>
Date: Sun, 8 May 88 12:37:54 MDT
Subject: Re: nesting of EVAL-WHENs
To: Jon L White <edsel!jonl@labrea.stanford.edu>
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Jon L White <edsel!jonl@labrea.stanford.edu>, Sat, 7 May 88 02:16:36 PDT
Hmmm. I suppose we could say that if both COMPILE and LOAD are
specified in the outer EVAL-WHEN, when the compiler is processing the
body to spit out the code to do the LOAD evaluation, it should not do
any more compile-time evaluation of nested subforms. This could be
modeled with our view of how EVAL-WHEN might be implemented as a macro
by having (EVAL-WHEN (COMPILE LOAD) ...) expand into a MACROLET, that
shadows EVAL-WHEN with a new definition which totally ignores the
COMPILE situation.
-Sandra
-------
∂09-May-88 0852 CL-Compiler-mailer proposals
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 May 88 08:52:42 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22751; Mon, 9 May 88 09:53:17 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805091553.AA22751@cs.utah.edu>
Date: Mon, 9 May 88 09:53:16 MDT
Subject: proposals
To: cl-compiler@sail.stanford.edu
You should be getting three proposals from me immediately following this
message. I would like to get these proposals (or some modified version
of them) distributed to the full X3J13 committee at the June meeting, so
that they could be voted on at the meeting after that. (It is probably
too late to hope for getting them up for a vote at the June meeting.)
So, please read them over. All of the proposals could use more work on
the "current practice" and "cost to implementors" sections, so if you
vendors out there want to get your names mentioned :-), send mail.
I will put together revised versions to incorporate comments/complaints.
-Sandra
-------
∂09-May-88 0854 CL-Compiler-mailer issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 May 88 08:53:57 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22789; Mon, 9 May 88 09:54:36 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805091554.AA22789@cs.utah.edu>
Date: Mon, 9 May 88 09:54:35 MDT
Subject: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: cl-compiler@sail.stanford.edu
Issue: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
References: CLtL pages 66-70, 143
Category: CLARIFICATION
Edit history: V1, 07 Oct 1987 Sandra Loosemore
V2, 15 Oct 1987 Sandra Loosemore
V3, 15 Jan 1988 Sandra Loosemore
V4, 06 May 1988 Sandra Loosemore
Problem Description:
Standard programming practices assume that, when calls to defining
macros such as DEFMACRO and DEFVAR are compiled, certain side-effects
occur that affect how the compiler processes subsequent forms.
However, these side-effects are not mentioned in CLtL, except for a
passing mention that macro definitions must be ``seen'' by the
compiler before it can compile calls to those macros correctly.
Proposal: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
(1) Certain defining macros, appearing within a file being processed
by COMPILE-FILE, normally have compile-time side effects which affect
how subsequent forms in the same file are compiled. The defining macros
and their specific side effects are as follows:
DEFTYPE: Type names defined via DEFTYPE must be recognized as valid in
subsequent type declarations.
DEFMACRO, DEFINE-MODIFY-MACRO: Macro definitions must be stored at compile
time, so that occurences of the macro later on in the file will be expanded
correctly. The body of the macro (but not necesarily its expansion) must
be evaluable at compile time.
DEFUN: An implementation may choose to store information about the
function for the purposes of compile-time error-checking (such as checking
the number of arguments on calls). Portable code should not rely on DEFUN
making the function definition available at compile time.
DEFVAR, DEFPARAMETER: The compiler must recognize that the variables
named by these forms have been proclaimed special. The initial value form
must not be evaluated at compile time.
DEFCONSTANT: An implementation may choose to store information about the
variable for the purposes of compile-time error-checking (such as checking
for rebinding of or assignment to the variable). If the initial value form
is a constant, an implementation may also choose to evaluate it at compile
time for the purposes of constant-folding.
DEFSETF, DEFINE-SETF-METHOD: SETF methods must be available during the
expansion of calls to SETF later on in the file. The body of
DEFINE-SETF-METHOD and the complex form of DEFSETF must be evaluable at
compile time.
DEFSTRUCT: The structure type name must be recognized as a valid type name
in declarations, as for DEFTYPE. The structure slot accessors must be made
known to SETF. In addition, further DEFSTRUCT definitions should be able
to :INCLUDE a structure type defined earlier in the file being compiled.
The functions which DEFSTRUCT generates, and the #S reader syntax, may or
may not be available at compile time.
(2) A model which explains how these compile-time side-effects happen is
that each defining macro expands into one or more EVAL-WHEN forms. The
bodies of the EVAL-WHEN forms contain code which causes the appropriate
information to be stored. Different information may be stored at
compile-time than when the defining macros are processed interpretively
or when the compiled file is loaded.
(3) The information stored by the defining macros at compile time may
or may not be available to the interpreter (either during or after
compilation), or during subsequent calls to COMPILE or COMPILE-FILE.
For example, the following code is nonportable because it assumes that the
compiler stores the macro definition of FOO where it is available to the
interpreter:
(defmacro foo (x) `(car ,x))
(eval-when (eval compile load)
(print (foo '(a b c))))
A portable way to do the same thing would be to include the macro definition
inside the EVAL-WHEN:
(eval-when (eval compile load)
(defmacro foo (x) `(car ,x))
(print (foo '(a b c))))
Rationale:
The proposal reflects standard programming practices. The primary purpose
of the proposal is to make an explicit statement that CL supports the
behavior that most programmers expect and many implementations already
provide.
Current Practice:
Many (probably most) Common Lisp implementations, including VaxLisp and
Lucid Lisp, are already largely in conformance.
Kyoto Common Lisp is a notable offender. By default, KCL evaluates *all*
top level forms as they are compiled, which is clearly in violation of the
behavior specified on p 69-70 of CLtL. There is a flag to disable the
compile-time evaluation, but then macros such as DEFMACRO, DEFVAR, etc. do
not make their definitions available at compile-time either.
Cost to implementors:
Making the defining macros expand into EVAL-WHENs to store the required
information is a simple and recommended implementation technique.
Cost to users:
Since CLtL does not specify whether and what compile-time side-effects
happen, any user code which relies on them is, strictly speaking,
nonportable. In practice, however, most programmers already expect
the behavior described in this proposal and will not find it to be
an incompatible change.
Benefits:
Adoption of the proposal will provide more definite guidelines on how to
write programs that will compile correctly under all CL implementations.
Discussion:
Reaction to an earlier version of this proposal on the CL mailing list was
overwhelmingly positive.
The only major criticism of this proposal I have heard is that it should
also include PROCLAIM. However, since PROCLAIM is not a macro, its
compile-time side effects cannot be handled using the same mechanism.
A separate proposal seems more appropriate.
-------
∂09-May-88 0855 CL-Compiler-mailer issue EVAL-WHEN-NON-TOP-LEVEL
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 May 88 08:54:55 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22855; Mon, 9 May 88 09:55:34 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805091555.AA22855@cs.utah.edu>
Date: Mon, 9 May 88 09:55:33 MDT
Subject: issue EVAL-WHEN-NON-TOP-LEVEL
To: cl-compiler@sail.stanford.edu
Issue: EVAL-WHEN-NON-TOP-LEVEL
References: CLtL p. 69-70
Issue DEFINING-MACROS-NON-TOP-LEVEL
Category: CLARIFICATION, ENHANCEMENT
Edit History: 6-May-88, V1 by Sandra Loosemore
Problem Description:
The current description of how the compiler should handle EVAL-WHEN
only makes sense when it appears as a top-level form in the file being
compiled. Other proposals being considered by the compiler cleanup
committee require that we clarify how the compiler should process
EVAL-WHENs appearing at non-top-level, such as within LET or FUNCTION
special forms.
Proposal: EVAL-WHEN-NON-TOP-LEVEL:CLARIFY
There are three possible processing situations which may be specified
in EVAL-WHEN. The interpreter pays attention to only the EVAL
situation, while the LOAD and COMPILE situations are handled by the
compiler.
The EVAL situation corresponds to the normal processing of the
interpreter. If EVAL is specified, the interpreter evaluates each
form in the body of the EVAL-WHEN as an implicit PROGN, using the
current lexical environment. If the EVAL situation is not specified,
then the interpreter must return NIL as the value of the EVAL-WHEN
form, without evaluating the body.
The LOAD situation corresponds to the normal processing of the
compiler. To the compiler, (EVAL-WHEN (LOAD) ...) is equivalent to a
PROGN form; the compiler simply arranges for the body to be
``evaluated'' in the lexical environment in which the EVAL-WHEN form
appears. If the LOAD situation is not specified, the compiler
arranges for the EVAL-WHEN form to return a value of NIL without
evaluating the body forms. (The name LOAD is something of a misnomer,
because ``evaluation'' happens not at LOAD time, but when the
EVAL-WHEN form would normally be ``evaluated''. For example, if an
EVAL-WHEN form appears in the body of a DEFUN, it is ``evaluated''
when that function is called.)
The EVAL and LOAD situations are therefore quite similar and
correspond to normal evaluation semantics. That is, one could
consider that each form and nested subform is implicitly wrapped with
an (EVAL-WHEN (EVAL LOAD) ...).
The COMPILE situation indicates that the compiler itself should
evaluate the body of the EVAL-WHEN form as an implicit PROGN in the
null lexical environment. During the evaluation, if a nested
EVAL-WHEN appears in the body, the interpreter follows its usual rule
of checking only whether or not the EVAL situation is specified to
decide whether or not the body of the nested EVAL-WHEN should be
processed.
If both the COMPILE and LOAD situations are specified, the compiler
first performs the evaluation for the COMPILE situation. Then, the
normal processing for the LOAD situation takes place, except that the
compile-time evaluation of nested (EVAL-WHEN (COMPILE) ...) forms in
the body is suppressed, preventing repeated evaluations of subforms.
(EVAL-WHEN (COMPILE) ...) should be used with caution in non-top-level
situations. For example, if the following appears as a top level form
in a file being compiled
(let ((x (some-hairy-computation)))
(eval-when (eval compile load) (print x)))
the variable X will be treated as special during the compile-time
evaluation, and the value printed will be its symbol-value. To
guarantee consistency between compile-time evaluation and the normal
processing, one should wrap the entire top-level form in an EVAL-WHEN,
as follows:
(eval-when (eval-compile load)
(let ((x (some-hairy-computation)))
(print x)))
Rationale:
The behavior of top-level EVAL-WHENs as specified in this proposal
remains almost identical to that specified in CLtL. The major
addition is specifying the lexical environment in which non-top-level
EVAL-WHENs are processed. It is clear that the COMPILE situation must
always be processed in the null lexical environment, since the actual
lexical environment is not available at compile time. Having the EVAL
and LOAD situations evaluate in the proper environment leads to
differing semantics, but it appears to be the behavior that most
people expect.
Suppression of COMPILE evaluations in nested EVAL-WHENs is necessary
to achieve certain desirable behaviors, such as the macro example in
section 4 of the DEFINING-MACROS-NON-TOP-LEVEL proposal.
Current Practice:
Cost to implementors:
Probably fairly minor in most implementations.
As an implementation technique, we suggest implementing EVAL-WHEN as a
macro which uses a state variable (rebound by EVAL, COMPILE, and
COMPILE-FILE) to keep track of the current context.
(defmacro eval-when (situations &body body)
(cond ((null *compiling-p*)
(if (member 'eval situations)
`(progn ,@body)
'nil))
((and (member 'compile situations) (member 'load situations))
(eval `(progn ,@body))
`(macrolet ((eval-when (situations &body body)
(if (member 'load situations)
`(progn ,@body)
'nil)))
,@body))
((member 'compile situations)
(eval `(progn ,@body))
'nil)
((member 'load situations)
`(progn ,@body))
(t 'nil)))
Cost to users:
Since CLtL does not currently specify what the meaning of EVAL-WHEN
forms at non-top-level is, existing code which depends on their use is
already nonportable. Preventing repeated evaluations of subforms when
EVAL-WHENs are nested is unlikely to cause any serious compatibility
problems, since the current model would already result in only a
single evaluation in the case when the code is processed
interpretively.
Benefits:
Clarifying the meaning of EVAL-WHEN allows the behavior of defining
macros such as DEFMACRO to be specified in terms of EVAL-WHEN. As a
side effect, it would then become meaningful for defining macros to
appear at other than top-level.
Discussion:
This proposal reflects what appears to be the consensus of the
compiler cleanup committee on this issue.
-------
∂09-May-88 0856 CL-Compiler-mailer issue DEFINING-MACROS-NON-TOP-LEVEL
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 May 88 08:56:13 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22960; Mon, 9 May 88 09:56:53 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805091556.AA22960@cs.utah.edu>
Date: Mon, 9 May 88 09:56:50 MDT
Subject: issue DEFINING-MACROS-NON-TOP-LEVEL
To: cl-compiler@sail.stanford.edu
Issue: DEFINING-MACROS-NON-TOP-LEVEL
References: CLtL p. 66-70, 143
Issue EVAL-WHEN-NON-TOP-LEVEL
Issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Category: CLARIFICATION, ENHANCEMENT
Edit History: 6-May-88, V1 by Sandra Loosemore
Problem Description:
CLtL leaves the interpretation of defining forms such as DEFMACRO and
DEFVAR that appear in other than top-level locations unspecified.
Resolution of other issues (EVAL-WHEN-NON-TOP-LEVEL and
COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS) now allows reasonable
semantics to be assigned to defining forms which appear at
non-top-level.
Proposal: DEFINING-MACROS-NON-TOP-LEVEL:ALLOW
(1) Clarify that while defining macros normally appear at top level,
it is meaningful to place them in non-top-level contexts and that the
compiler must handle them properly in all situations. Remove the
language on p. 66 of CLtL which states that the compiler is not
required to recognize defining macros at other than top-level.
(2) The proposal COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
defines a model for specifying how defining macros work. To
summarize, the expansion of the macro (rather than its expander
function) is responsible for storing information about the definition.
Compile-time side effects are typically handled by including one or
more EVAL-WHEN forms in the expansion. Although a compiler may choose
some other implementation, such as treating defining macros as
implementation-specific special forms, the semantics must remain the
same.
(3) Defining macros which define functional objects (such as DEFUN and
DEFMACRO) must ensure that the functions are defined in the lexical
environment in which the defining macro appears. In the model
referred to above, this would normally be implemented by producing a
FUNCTION special form in the macro expansion. For example, the
following code causes the function BAR to be closed over the variable
X:
(let ((x (some-hairy-computation)))
(defun bar (y) (+ x y)))
(4) The language on p. 145 of CLtL, which states that macro functions
are defined in the null lexical environment, should be removed.
Instead, defining forms such as DEFMACRO which make a functional
definition available at the compile time use the environment must
normally appear inside an explicit (EVAL-WHEN (COMPILE) ...) to ensure
that the correct lexical environment is seen.
An example may help clarify why this is necessary. The code fragment
(let ((x (some-hairy-computation)))
(defmacro bar-macro (y) `(+ ,x ,y)))
would macroexpand into something similar to
(let ((x (some-hairy-computation)))
(eval-when (eval compile load)
(setf (macro-function 'bar-macro)
#'(lambda (form env)
(let ((y (second form)))
`(+ ,x ,y))))
'bar-macro))
Since the rules for (EVAL-WHEN (COMPILE) ...) state that evaluation takes
place in the null lexical environment, in this situation X would be treated
as a special variable within the macro function. However, in the EVAL or
LOAD situations, the lexical value of X would be used. To ensure
consistency, the correct definition would be:
(eval-when (eval compile load)
(let ((x (some-hairy-computation)))
(defmacro bar (y) `(+ ,x ,y))))
Rationale:
The notion of a ``top-level form'' is rather confused. There has been
a suggestion that the notion of a top-level form should be extended to
include forms in the body of a top-level LET, to allow forms such as
DEFUN to be meaningful there. However, we feel that a cleaner
solution is to remove the restrictions on the placement of defining
macros altogether.
Current Practice:
Cost to implementors:
Cost to users:
None. This is a compatible extension.
Benefits:
The notion of top-level forms as being somehow special is removed from
the language. Allowing defining macros to appear anywhere instead of
restricting them to certain positions results in a cleaner language
design.
Discussion:
-------
∂10-May-88 2314 CL-Compiler-mailer subcommittee meeting(s)
Received: from ucbarpa.Berkeley.EDU by SAIL.Stanford.EDU with TCP; 10 May 88 23:14:11 PDT
Received: by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA11863; Tue, 10 May 88 23:14:03 PDT
Received: by franz (5.5/3.14)
id AA13520; Tue, 10 May 88 22:29:34 PDT
Received: by feast (5.5/3.14)
id AA01569; Wed, 11 May 88 01:20:30 EDT
Date: Wed, 11 May 88 01:20:30 EDT
From: franz!feast!smh@ucbarpa.Berkeley.EDU (Steven M. Haflich)
Message-Id: <8805110520.AA01569@feast>
To: cl-compiler@sail.stanford.edu
Subject: subcommittee meeting(s)
Time to schedule the compiler-cleanup subcommittee for June X3J13.
Last time in Palo Alto we actually made some progress. Now we need to
continue towards real written proposals. Be there or be interpreted!
Scheduling is tricky, as ever, paarticular acommodating travel for
out-of-towners. Several of us are involved with the Definition Specs
meeting 3:00-5:30 Tuesday. We probably need a fair amount of time to
work through details -- a single 2-3 hour meeting probably wouldn't be
enough. So either we schedule a single long meeting, or two shorter
ones.
I would be very happy with a Tuesday evening meeting and a Thursday
evening or Friday morning meeting. This might be convenient for
out-of-towners. (I *think* I would be able to find a meeting place,
assuming Symbolics might not be available outside office hours.) The
alternative would be to start early Tuesday, but this would require an
extra night for West Coast people.
If you have particular travel and/or time restrictions, please
respond asap so I can work out the details. If I *don't* hear, I'll
just make an arbitrary decision.
∂12-May-88 1826 CL-Compiler-mailer subcommittee meeting(s)
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 12 May 88 18:25:54 PDT
Received: by labrea.stanford.edu; Thu, 12 May 88 18:12:48 PDT
Received: from bhopal.lucid.com by edsel id AA09585g; Thu, 12 May 88 18:17:42 PDT
Received: by bhopal id AA23990g; Thu, 12 May 88 18:20:46 PDT
Date: Thu, 12 May 88 18:20:46 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805130120.AA23990@bhopal.lucid.com>
To: franz!feast!smh@ucbarpa.berkeley.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Steven M. Haflich's message of Wed, 11 May 88 01:20:30 EDT <8805110520.AA01569@feast>
Subject: subcommittee meeting(s)
Since traving West-to-East means a three-hour time shift in the "wrong"
direction, I strongly prefer late-afternoon and evening meetings to
any morning meetings.
-- JonL --
∂16-May-88 1244 CL-Compiler-mailer Re: COMPILE-FILE-OF-TOP-LEVEL-FORMS
Received: from hudson.dec.com by SAIL.Stanford.EDU with TCP; 16 May 88 12:44:39 PDT
Date: 16 May 88 15:32:00 EDT
From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Subject: Re: COMPILE-FILE-OF-TOP-LEVEL-FORMS
To: "cl-compiler" <cl-compiler@sail.stanford.edu>
cc: vanroggen
Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
It's good to some of these things written down. Here are my comments
so far...
I think the issue name is a bit too general--how about
COMPILE-FILE-OF-DEFINING-MACROS, since it just talks about
DEFxxx forms, with the "top-level" assumed.
If we don't want to address inter-file dependencies in this issue,
we should say so explicitly.
Although this is an issue that comes with PROCLAIM, it's probably
worthwhile mentioning that when COMPILE-FILE sees a DEFUN, it may
decide to keep the body of the function around due to INLINE
proclamations. VAX LISP requires INLINE proclamations to come
before the corresponding DEFUNs, because we don't want to keep around
all the source code ever seen just in case an INLINE proclamation/declaration
might come much later.
"If the initial value form [of a DEFCONSTANT] is a constant, an
implementation may also choose to evaluate it at compile time for
the purposes of constant-folding."
Firstly, if the value is a constant, it may be evaluated at any time--
so this sentence doesn't say much. [Or is the referent of "it" the
DEFCONSTANT expression?] Secondly, I think it's more important to state
what an implementation -cannot- do, much as was stated for DEFVAR.
I think of DEFCONSTANT and DEFPARAMETER being very similar, except that
constants can't be set or bound. I don't see why that would suddenly
allow the compiler to evaluate the inital value form at compile time.
So we should say that the initial value form must not be evaluated at
compile time.
For DEFSETF and DEFINE-SETF-METHOD, add the comment (as is included
for DEFMACRO) that the expansion needn't be evaluable at compile time.
Question: must the expansion of a DEFTYPE be a legitimate type at compile
time?
---Walter
------
∂16-May-88 2307 CL-Compiler-mailer issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 16 May 88 23:07:21 PDT
Received: by labrea.stanford.edu; Mon, 16 May 88 23:07:44 PDT
Received: from bhopal.lucid.com by edsel id AA28744g; Mon, 16 May 88 22:57:04 PDT
Received: by bhopal id AA03382g; Mon, 16 May 88 23:00:22 PDT
Date: Mon, 16 May 88 23:00:22 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805170600.AA03382@bhopal.lucid.com>
To: sandra@cs.utah.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Sandra J Loosemore's message of Mon, 9 May 88 09:54:35 MDT <8805091554.AA22789@cs.utah.edu>
Subject: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
One thing bothers me muchly about this proposal -- it re-inforces the old
MacLisp notion of "specially noticing" certain forms at top level without
evaluating them; in particular the MacLisp Compiler had a separate database
which held macro definitions "noticed" in the file being compiled, but
which hadn't been explicitly evaluated.
What I particularly dislike is the half-supported status of "noticed" things;
why will a macro be expandable by the compiler but not by the interpreter?
The many ways in which things can be "noticed", and the meaning of "notice",
is very opaque.
Instead, I'd prefer the issue to be simply "To Evaluate, or Not to
Evaluate, That Is the Question". In short, every form should fall
into one of four categories:
(1) Function definition, in which case not only is the body compiled
but the compiler is permitted to "remember" certain aspects of
the function, such as argument spectrum for subsequent user-friendly
warning messages, and such as source-code for subsequent INLINEing.
[Macro definitions can come under this clause too; but they could
also be listed both in (1) and (2).]
(2) Explicitly-listed form that is implicitly eval-when(eval compile load);
"implicitly" means, "if the user didn't wrap an eval-when around it,
then the compiler puts the 'implicit' one in;" however, any user
supplied eval-when overrides this implicit behaviour. There is already
a precedent with several of the "Seven Extremely Randoms".
(3) An EVAL-WHEN form; explicit semantics for such toplevel forms will be
forthcoming; anyway, it ought to be obvious.
(4) Any other form not in (1) through (3); such is merely compiled and
"shoved" out into the compiler output file.
Because of the need to treat IN-PACKAGE and possibly other "7 randoms"
this way, I don't think we could every reduce (2) to the null set. I admit
that putting too many functions in it would confuse things (making it
harder to remember just what was there). But for starters, why not
all the DEF... forms you listed in your proposal, except for DEFUN and
DEFVAR (and DEFPARAMETER, which is a trivial variant of DEFVAR). This
would mean every CLtL DEF... form (except for the exceptions) is implicitly
evaluated during compilation; when this is undesirable, the user would have
the burden of explicitly wrapping eval-when (eval load) around the form.
I fear that my simplified proposal is what you initially offered a long
time ago, and were beaten back on. But I offer my support for it now,
if clarifying is what you want to do.
-- JonL --
∂17-May-88 0739 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 17 May 88 07:39:32 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA24901; Tue, 17 May 88 08:39:05 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805171439.AA24901@cs.utah.edu>
Date: Tue, 17 May 88 08:39:04 MDT
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: edsel!jonl@labrea.stanford.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Jon L White <edsel!jonl@labrea.stanford.edu>, Mon, 16 May 88 23:00:22 PDT
Date: Mon, 16 May 88 23:00:22 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
One thing bothers me muchly about this proposal -- it re-inforces the old
MacLisp notion of "specially noticing" certain forms at top level without
evaluating them; in particular the MacLisp Compiler had a separate database
which held macro definitions "noticed" in the file being compiled, but
which hadn't been explicitly evaluated.
That situation was exactly what this proposal (actually group of
proposals) was trying to get rid of, not re-inforce. The compiler need
not do any "special noticing" of these defining macros at all, because
the model Steve and I have proposed is that the macros expand into
EVAL-WHENs to wrap the actions that should be performed at
compile-time. All the compiler needs to recognize is EVAL-WHEN (and the
N ugly package functions). The actions, such as storing macro
definitions, may be (but are not required to be) handled identically in
both the interpreter and the compiler.
What I particularly dislike is the half-supported status of "noticed" things;
why will a macro be expandable by the compiler but not by the interpreter?
I don't understand this. The compiler must expand all the macros it runs
across, and so must the interpreter.
The big problem I have with your simplified counterproposal is that few
(if any) implementations already work that way, and I do not believe
that the behavior it specifies is what users really want or expect to
happen.
-Sandra
-------
∂17-May-88 2241 CL-Compiler-mailer issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 17 May 88 22:41:40 PDT
Received: by labrea.stanford.edu; Tue, 17 May 88 22:42:08 PDT
Received: from bhopal.lucid.com by edsel id AA03485g; Tue, 17 May 88 22:30:18 PDT
Received: by bhopal id AA07755g; Tue, 17 May 88 22:33:43 PDT
Date: Tue, 17 May 88 22:33:43 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805180533.AA07755@bhopal.lucid.com>
To: sandra@cs.utah.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Sandra J Loosemore's message of Tue, 17 May 88 08:39:04 MDT <8805171439.AA24901@cs.utah.edu>
Subject: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
re: That situation was exactly what this proposal (actually group of
proposals) was trying to get rid of, not re-inforce. ...
the model Steve and I have proposed is that the macros expand into
EVAL-WHENs to wrap the actions that should be performed at
compile-time.
Gleeep! I've completly misread the intent of your proposal. I believe
I misread it because the first n paragraphs of your PROPOSAL: section
reads like a problem description. Two things need to be done (so I
think) to clarify this: (1) very early mention that this is what you
want to happen -- that compiler "noticing" is merely reduced to usages
of EVAL-WHEN; (2) be much more specific as to what gets EVALuated at
compile time -- the listing of desirable effects in the "proposal"
section is ok, but not specific enough to believe that they are all
being accomplished via normal EVAL-WHEN(...COMPILE...).
re: What I particularly dislike is the half-supported status of "noticed"
things; why will a macro be expandable by the compiler but not by the
interpreter?
I don't understand this. The compiler must expand all the macros it runs
across, and so must the interpreter.
Well you yourself added the phrase:
The actions, such as storing macro definitions, may be (but are not
required to be) handled identically in both the interpreter and the
compiler.
and it is this uncertainty about "not required to be" -- about the non-
equivalence of EVAL and EVAL-WHEN(...COMPILE...) -- that bothers me.
True, no implementation operates exactly like my simplified counter. But
they are not far from it. Probably most are in accord with it on DEFUN,
DEFVAR, and DEFPARAMETER; and Lucid is in accord also on DEFCONSTANT,
DEFMACRO, and DEFTYPE. Also Lucid is "mostly" in accord on DEFSTRUCT in
that it does exactly the same thing as evaluating the defstruct, but doesn't
actually install anything in the symbol-function cells (i.e., it makes
the TYPE entry, makes compiler macros for the functions etc.).
The hardest "pill" to swallow is to decide to make DEFSTRUCT, DEFMACRO,
and DEFTYPE implicitly eval-when(eval compile load) Actually, the
"simplified counter" doesn't depend on which of the varous forms are
promoted to the "implicit" status and which aren't -- it merely tries to
make a uniform interpretation when interpreting and compileing forms that
affect the compilation process.
-- JonL --
∂18-May-88 1104 CL-Compiler-mailer issue EVAL-WHEN-NON-TOP-LEVEL
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 18 May 88 11:04:00 PDT
Received: by labrea.stanford.edu; Wed, 18 May 88 02:14:56 PDT
Received: from bhopal.lucid.com by edsel id AA04028g; Wed, 18 May 88 01:59:26 PDT
Received: by bhopal id AA08279g; Wed, 18 May 88 02:02:52 PDT
Date: Wed, 18 May 88 02:02:52 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805180902.AA08279@bhopal.lucid.com>
To: sandra@cs.utah.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Sandra J Loosemore's message of Mon, 9 May 88 09:55:33 MDT <8805091555.AA22855@cs.utah.edu>
Subject: issue EVAL-WHEN-NON-TOP-LEVEL
The early part of the Proposal: section probably ought to outline our
intent in giving ordinary macro semantics to EVAL-WHEN -- it is so that
an piece of source code will either be "processed" as if the body of the
eval-when is there, or as if it were not there, depending on the dynamic
state of the processor:
Original Source | Situation Applies | Situation Doesn't Apply
-----------------------+------------------------+----------------------------
| |
(defun foo (x) | (defun foo (x) | (defun foo (x)
(step1 x) | (step1 x) | (step1 x)
(eval-when (...) | (step2 x) | nil
(step2 x)) | (step2 x)) | (step3 x))
(step3 x)) | |
On can infer this from a careful reading of the proposal, but the
overwhelming simplicity of making eval-when a small macro is lost "in the
woods". This top-level view of the proposal ought to be said very early
in the proposal, rather than starting out with a myriad of details about
how the various situations are treated.
I note also that you implicitly assume a dynamic variable *compiling-p*?
This will have to be spelled out in detail, much as in my note of
25 Mar 88 23:21:23 PST "Eval-When -- a radical view"; simply being
"in the compiler" isn't enough since EVAL may have to bind this variable
to nil (or do the equivalent -- Rob points out that we don't really
want to tie down the implementation to an actual dynamic variable, but
rather to the semantics give by the example code).
I very much like the idea of shadowing eval-when with a macrolet in the
situation where there might be nested eval-when's and the outter one has
at least a 'compile' situation. In fact, the trial code I sent out in
the msg "Eval-When -- a radical view" doesn't work right; the attempt
to identify this circumstance with a dynamic binding of a state variable
(to :eval-before-compile) is wrong, since it really is a lexical effect
that is needed, not a dynamic one.
Finally, I had a bit of trouble following all the logic in all the
cond clauses of the sample defmacro for EVAL-WHEN. Could I offer a
rewrite, with effusive commentary, that breaks it down into basically
two cases: the "hard" case (presented first) and the "easy" one.
(defmacro eval-when (situations &body body)
(cond ((and *compiling-p*
(member 'compile situations))
;; Situation Applies: The hard case. Compiling, and evaluation
;; is required at compile time too.
(eval `(progn ,@body))
(if (member 'load situations)
;; Allow normal processing by 'compile-form-to-file',
;; except ignore sub requests for compile-time evaluation.
`(macrolet ((eval-when (situations &body body)
(if (member 'load situations)
`(PROGN ,@body)
'NIL)))
,@body)
;; or skip processing by 'compile-form-to-file'
`NIL))
((if *compiling-p*
(member 'load situations)
(member 'eval situations))
;; Situation Applies: The easy case. Just return the body code
;; for normal processing by 'eval' or 'compile-form-to-file'.
`(PROGN ,@body))
(t
;; Hmmm, 'situation' just doesn't apply!
`NIL)))
-- JonL --
∂18-May-88 1152 CL-Compiler-mailer proposals
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 18 May 88 11:52:03 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA29255; Wed, 18 May 88 08:55:04 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805181455.AA29255@cs.utah.edu>
Date: Wed, 18 May 88 08:55:03 MDT
Subject: proposals
To: cl-compiler@sail.stanford.edu
Unless I hear any objections Real Soon Now, I'm going to write up revised
versions of the proposals I sent out before to incorporate the suggestions
I've received and clean up the wording. I hope to be able to get them out
by the weekend.
-Sandra
-------
∂19-May-88 1012 CL-Compiler-mailer subcommittee meeting(s)
Received: from ucbarpa.Berkeley.EDU by SAIL.Stanford.EDU with TCP; 19 May 88 10:12:27 PDT
Received: by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA01979; Thu, 19 May 88 10:11:41 PDT
Received: by franz (3.2/3.14)
id AA05387; Thu, 19 May 88 10:03:41 PDT
Received: by feast (5.5/3.14)
id AA00668; Thu, 19 May 88 12:54:04 EDT
Date: Thu, 19 May 88 12:54:04 EDT
From: franz!feast!smh@ucbarpa.Berkeley.EDU (Steven M. Haflich)
Message-Id: <8805191654.AA00668@feast>
To: franz!cs.utah.edu!sandra
Cc: franz!sail.stanford.edu!cl-compiler
In-Reply-To: Sandra J Loosemore's message of Wed, 18 May 88 09:03:42 MDT <8805181503.AA29510@cs.utah.edu>
Subject: subcommittee meeting(s)
From: fridge!ucbarpa!cs.utah.edu!sandra (Sandra J Loosemore)
On the assumption that we will be meeting on Tuesday evening and on
Friday, I've arranged to arrive late Tuesday afternoon. (I will actually
be staying until Sunday morning with the idea of spending all day Saturday
visiting the local bookstores....)
Hereby announced. Meetings will be Tuesday evening and Friday
morning, unless someone makes a compelling counterproposal. I'll
further suggest that those of us who can should start Tuesday over
dinner at one of the many fine but reasonably-priced eating
establishments in Cambridge. It would be useful to know when people
become available so we can pick exact times, but there's no urgency.
It's been overheard from the Character Subcommittee that evening
meetings at Symbolics are impossible because of security. Therefore
I've arrange with Greenblatt to use a conference room at Gigamos.
Gigamos easy to get to -- it is within long walking distance of
Symbolics, and just steps from the Central Square subway stop. I'll
post directions etc. later.
P.S.: Right now someone is working on franz's mailer, and it sometimes
generates bogus return addresses. No problem -- I'll still receive
anything cc'd to cl-compiler@sail.
∂20-May-88 0825 CL-Compiler-mailer issue EVAL-WHEN-NON-TOP-LEVEL
Received: from hudson.dec.com by SAIL.Stanford.EDU with TCP; 20 May 88 08:25:46 PDT
Date: 20 May 88 11:19:00 EDT
From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Subject: issue EVAL-WHEN-NON-TOP-LEVEL
To: "cl-compiler" <cl-compiler@sail.stanford.edu>
cc: vanroggen
Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Overall, this proposal looks pretty good, if a clarification and "compatible"
extension is what we want.
I think that in addition to specifying the environments for the different
situations, the major change in this proposal may appear to be the meaning of
the LOAD situation. I would like to believe that the intent of the LOAD
situation has always been to make the body of the EVAL-WHEN be compiled, not
the more obvious intent (judging by the name) of EVALuating the body when the
compiled file is being LOADed.
The latter interpretation is perfectly consistent with the former as long as
the EVAL-WHEN is at top-level in the file. Since we want to assign a meaning to
EVAL-WHEN when not at top-level, the former interpretation makes more sense and
would be compatible between the old and the new semantics.
Another reason why this interpretation is necessary is that non-top-level
EVAL-WHEN's ought to work fine when COMPILE is being used to compile
functions, not just when used in files being processed by COMPILE-FILE.
I believe that explicitly stating this interpretation will make it easier
for people to understand why the LOAD situation doesn't mean what they may
think it means. Although I believe my interpretation is what you mean to
say in
To the compiler, (EVAL-WHEN (LOAD) ...) is equivalent to a
PROGN form; the compiler simply arranges for the body to be
``evaluated'' in the lexical environment in which the EVAL-WHEN form
appears.
it might still not be clear to some readers. [But the macro definition
of EVAL-WHEN helps a lot.] Perhaps a historical note about compilers
normally being file compilers will help also.
The related thing which people might be confused with is what happens
with "#,". The reason why I suggested this proposal, which I agree with,
might not be sufficient is that it doesn't address the ability to
evaluate forms at LOAD time. But maybe this proposal along with another
one to add a special form to do LOAD-time evaluation for side-effects
and constant-values will be acceptable.
A major nit (!?): Isn't there a cleanup proposal to disallow lexically
binding special-forms in FLET, LABELS, and MACROLET? If so, your
EVAL-WHEN macro is doing a no-no. You might want to change the statement
from "suggested implementation technique" to "implemented as if".
For the Current Practice section, VAX LISP implements the proposed
changes already, except that it doesn't always substitute NIL when the
situation doesn't apply. (There are times when the whole form just
disappears rather than returning NIL.)
---Walter
------
∂20-May-88 1158 CL-Compiler-mailer Re: issue EVAL-WHEN-NON-TOP-LEVEL
Received: from FRED.SLISP.CS.CMU.EDU by SAIL.Stanford.EDU with TCP; 20 May 88 11:58:12 PDT
Received: from FRED.SLISP.CS.CMU.EDU by FRED.SLISP.CS.CMU.EDU; 20 May 88 14:59:54 EDT
To: sandra@cs.utah.edu (Sandra J Loosemore)
cc: cl-compiler@sail.stanford.edu
Subject: Re: issue EVAL-WHEN-NON-TOP-LEVEL
In-reply-to: Your message of Mon, 09 May 88 09:55:33 -0600.
<8805091555.AA22855@cs.utah.edu>
Date: Fri, 20 May 88 14:59:13 EDT
From: Rob.MacLachlan@WB1.CS.CMU.EDU
This is a reasonable approach to making EVAL-WHEN well defined, but there
seems to be a problem when the COMPILE situation is specified without the
EVAL situation. In this form, I believe (FOO) would never be evaluated in
any context, which is definitely an incompatible change:
(eval-when (compile)
(eval-when (compile)
(foo)))
Admittedly, I have argued in the past that it is never meaningful to
specify the COMPILE situation without the EVAL situation, but if the intent
is to fix up EVAL-WHEN, then we should attempt to be as compatible as
possible.
But perhaps this is worked around by the usage of *in-the-compiler*? It
definitely needs to be made clearer what exactly is being done with that
varaible where. But if my above interpretation of nested uses of the
COMPILE situation is incorrect, then the text description should also be
changed, since it seems to be consistent with my interpretation.
As far as explanation of what EVAL-WHEN does, I think there should be
explicit mention of the fact that only the outermost use of the COMPILE
situation nulls the evaluation environment. This implied by the sample
implementation, and is exploited by your DEFMACRO environment example, but
should be made more explicit.
I agree with Jonl's remarks about the presentation of the proposal.
Rob
∂20-May-88 1208 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from FRED.SLISP.CS.CMU.EDU by SAIL.Stanford.EDU with TCP; 20 May 88 12:08:19 PDT
Received: from FRED.SLISP.CS.CMU.EDU by FRED.SLISP.CS.CMU.EDU; 20 May 88 15:09:55 EDT
To: sandra@cs.utah.edu (Sandra J Loosemore)
cc: cl-compiler@sail.stanford.edu
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
In-reply-to: Your message of Mon, 09 May 88 09:54:35 -0600.
<8805091554.AA22789@cs.utah.edu>
Date: Fri, 20 May 88 15:09:45 EDT
From: Rob.MacLachlan@WB1.CS.CMU.EDU
This is a fair summary of current practice, but I would rather push through
a proposal that is more aggressive in defining the exact effects of
compiler processing.
Like Jonl, I favor saying that forms like DEFMACRO are actually truly,
honest to God evaluated by the compiler. This could be done by an
expansion that includes an EVAL-WHEN, but it should be required that all
Common Lisp semantics of evaluation of that defining form should be present
in the compiler environment after the implicit evaluation.
It could be a bit icky actually installing the DEFSTRUCT slot accessors,
but this could be finessed by pretending that the slot accessors expand to
DEFUNs outside of the EVAL-WHEN.
I strongly, totally, completely disagree with VanRoggen's remarks about
DEFCONSTANT. From my perspective, the reason for DEFCONSTANT is permissive
rather restrictive. You define constants so that the compiler can use
information about that name at compile time. I believe that DEFCONSTANT
should also be implicitly evaluated at compile time. This means that the
value form *must always* be evaluable at compile time. This is a slight
departure from current practice, but a sensible and useful one.
Rob
∂20-May-88 1229 CL-Compiler-mailer Re: issue EVAL-WHEN-NON-TOP-LEVEL
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 20 May 88 12:29:53 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA05454; Fri, 20 May 88 13:29:59 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805201929.AA05454@cs.utah.edu>
Date: Fri, 20 May 88 13:29:58 MDT
Subject: Re: issue EVAL-WHEN-NON-TOP-LEVEL
To: Rob.MacLachlan@wb1.cs.cmu.edu
Cc: sandra@cs.utah.edu (Sandra J Loosemore), cl-compiler@sail.stanford.edu
In-Reply-To: Rob.MacLachlan@WB1.CS.CMU.EDU, Fri, 20 May 88 14:59:13 EDT
> Date: Fri, 20 May 88 14:59:13 EDT
> From: Rob.MacLachlan@WB1.CS.CMU.EDU
>
> This is a reasonable approach to making EVAL-WHEN well defined, but there
> seems to be a problem when the COMPILE situation is specified without the
> EVAL situation. In this form, I believe (FOO) would never be evaluated in
> any context, which is definitely an incompatible change:
> (eval-when (compile)
> (eval-when (compile)
> (foo)))
Yes, you are correct that under the current proposal, (foo) would never
be evaluated. I do not think it is "definitely" an incompatible change,
however. The current wording in CLtL seems to leave this behavior
unspecified and I don't know what the original intention was.
-Sandra
-------
∂20-May-88 1303 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 20 May 88 13:03:39 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA06503; Fri, 20 May 88 14:03:57 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805202003.AA06503@cs.utah.edu>
Date: Fri, 20 May 88 14:03:55 MDT
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: Rob.MacLachlan@wb1.cs.cmu.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Rob.MacLachlan@WB1.CS.CMU.EDU, Fri, 20 May 88 15:09:45 EDT
> Date: Fri, 20 May 88 15:09:45 EDT
> From: Rob.MacLachlan@WB1.CS.CMU.EDU
>
> Like Jonl, I favor saying that forms like DEFMACRO are actually truly,
> honest to God evaluated by the compiler. This could be done by an
> expansion that includes an EVAL-WHEN, but it should be required that all
> Common Lisp semantics of evaluation of that defining form should be present
> in the compiler environment after the implicit evaluation.
>
> It could be a bit icky actually installing the DEFSTRUCT slot accessors,
> but this could be finessed by pretending that the slot accessors expand to
> DEFUNs outside of the EVAL-WHEN.
These two paragraphs seem mutually contradictory. If you want to make
all of the defining macros implicitly EVAL-WHEN (EVAL COMPILE LOAD), like
the N random package functions, then you're going to get the defstruct
slot accessor functions defined at compile time, too. If you want the
defining macros to make some things available at compile time and other
things not, I think you either have to use EVAL-WHEN in the expansion
or have the compiler treat every one of these guys like a special form.
Again, the proposal as written appears to be fairly close to current
practice. Other than KCL, I don't know of any implementation that fully
evaluates DEFUN forms at compile time, and I don't know of any
implementation that doesn't do something special with DEFMACRO and
DEFVAR. In some implementations, the compile-time side-effects of
DEFMACRO make the macro defined in exactly the same way as if the form
had been evaluated by the interpreter, and in others the macro
definition is stored someplace where the compiler can see it but the
interpreter can't. Some people have made a fairly strong argument that
compilation side-effects should not affect the interpreter at all.
I think it would be nice to be able to definitely specify one way or the
other, either that the side-effects must be identical in the compiler to
what they are in the interpreter, or that the side effects must not be
visible to the interpreter at all. However, I think the diversity of
opinion on this issue might prevent us from getting the rest of the
proposal through to the full committee, and I think it is *very*
important that we do that as soon as we can. That is why the current
proposal explicitly leaves this behavior unspecified. If we eventually
reach agreement to tighten it up one way or the other later on, there is
nothing to prevent us from presenting another proposal to amend this
one. I just don't see that happening in the next few weeks.
-Sandra
-------
∂20-May-88 1354 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from FRED.SLISP.CS.CMU.EDU by SAIL.Stanford.EDU with TCP; 20 May 88 13:54:26 PDT
Received: from FRED.SLISP.CS.CMU.EDU by FRED.SLISP.CS.CMU.EDU; 20 May 88 16:55:23 EDT
To: sandra@cs.utah.edu (Sandra J Loosemore)
cc: cl-compiler@sail.stanford.edu
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
In-reply-to: Your message of Fri, 20 May 88 14:03:55 -0600.
<8805202003.AA06503@cs.utah.edu>
Date: Fri, 20 May 88 16:55:14 EDT
From: Rob.MacLachlan@WB1.CS.CMU.EDU
From: sandra@cs.utah.edu (Sandra J Loosemore)
Date: Fri, 20 May 88 14:03:55 MDT
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: Rob.MacLachlan@wb1.cs.cmu.edu
> Date: Fri, 20 May 88 15:09:45 EDT
> From: Rob.MacLachlan@WB1.CS.CMU.EDU
>
> Like Jonl, I favor saying that forms like DEFMACRO are actually truly,
> honest to God evaluated by the compiler.
[...] These two paragraphs seem mutually contradictory.
Well, not in my intent. I don't include DEFUN in "forms like DEFMACRO".
The "forms like DEFMACRO" are:
defmacro
deftype
defstruct
define-setf-method
defsetf
defconstant
As a codification of current practice, the proposal is fine, but it doesn't
go nearly as far in specification as a good language design should.
Vagueness in specification is a powerful tool, but you shouldn't be vague
for no good reason. The main reason that current practice is so diverse is
that this stuff was never standardized on, and for most programs *it
doesn't matter* as long as it falls within the general range you outline.
The problem with not being definite is that it encourages non-portability,
since the few programs that do care will work differently on different
implementations.
Having said that, I point out that I have no objection to this proposal
other than that it doesn't require the DEFCONSTANT value form to be
compile-time evaluable. In all other ways it is compatible with my
compiler cleanup proposal, since its definition is so inclusive.
Rob
∂20-May-88 1533 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 20 May 88 15:33:20 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA12692; Fri, 20 May 88 16:33:49 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805202233.AA12692@cs.utah.edu>
Date: Fri, 20 May 88 16:33:47 MDT
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: Rob.MacLachlan@wb1.cs.cmu.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Rob.MacLachlan@WB1.CS.CMU.EDU, Fri, 20 May 88 16:55:14 EDT
I guess I'm not sure exactly what I should be more specific about in
this proposal, and how specific you all would like it to be. I don't
think it would be appropriate to give code examples and say things like
"DEFMACRO *must* expand into *exactly* this set of forms". The hooks
used by DEFSETF, for example, are necessarily quite implementation-specific
and it would be pointless to try to dictate what they must be.
What I've been trying to do is lay out what users must do to ensure that
their code is portable, and what implementions must and must not do.
Walter has already pointed out some particular things he'd like
mentioned, and if anybody else has something specific to add, I'd be
happy to hear about it. I know I've left some things out just because
I didn't happen to think of them at the time I wrote this proposal!
-Sandra
-------
∂20-May-88 1627 CL-Compiler-mailer Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Received: from FRED.SLISP.CS.CMU.EDU by SAIL.Stanford.EDU with TCP; 20 May 88 16:27:14 PDT
Received: from FRED.SLISP.CS.CMU.EDU by FRED.SLISP.CS.CMU.EDU; 20 May 88 18:55:14 EDT
To: sandra@cs.utah.edu (Sandra J Loosemore)
cc: cl-compiler@sail.stanford.edu
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
In-reply-to: Your message of Fri, 20 May 88 16:33:47 -0600.
<8805202233.AA12692@cs.utah.edu>
Date: Fri, 20 May 88 18:55:09 EDT
From: Rob.MacLachlan@WB1.CS.CMU.EDU
From: sandra@cs.utah.edu (Sandra J Loosemore)
Date: Fri, 20 May 88 16:33:47 MDT
Subject: Re: issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
To: Rob.MacLachlan@wb1.cs.cmu.edu
I guess I'm not sure exactly what I should be more specific about in
this proposal, and how specific you all would like it to be.
This is the "compiler environment" issue. Your proposal allows
implementations to attempt to maintain a separate compiler namespace. This
capability is unnecessary for non-system code, and in the absence of
first-class environments, is too complex and/or vague to reasonably
specify.
Saying that the compile-time effect of processing a defining form is
required to be equivalent to that of evaluating it is more specific, and
not compatible with the concept of a compiler pseudo-environment. In my
proposal I do allow that the compiler environment be disjoint from the
environment that compile-file is called in, but the compiler environment
must be a "real" environment.
The fact that systems need some way to protect the running Lisp from
compilation of system definitions is not an argument against flushing the
compiler environment as a Common Lisp concept. Any Lisp system will
provide extensions that aid in bootstrapping the system; kludgey compiler
environment facilities can be enabled by a switch.
Once again, it isn't crucial that this issue be resolved now, since all
reasonable solutions are allowed by your proposal. The only thing I
strongly object to is the treatment of the DEFCONSTANT value form.
Rob
∂20-May-88 1647 CL-Compiler-mailer Re: issue EVAL-WHEN-NON-TOP-LEVEL
Received: from FRED.SLISP.CS.CMU.EDU by SAIL.Stanford.EDU with TCP; 20 May 88 16:47:26 PDT
Received: from FRED.SLISP.CS.CMU.EDU by FRED.SLISP.CS.CMU.EDU; 20 May 88 17:04:53 EDT
To: sandra@cs.utah.edu (Sandra J Loosemore)
cc: cl-compiler@sail.stanford.edu
Subject: Re: issue EVAL-WHEN-NON-TOP-LEVEL
In-reply-to: Your message of Fri, 20 May 88 13:29:58 -0600.
<8805201929.AA05454@cs.utah.edu>
Date: Fri, 20 May 88 17:04:48 EDT
From: Rob.MacLachlan@WB1.CS.CMU.EDU
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805201929.AA05454@cs.utah.edu>
Date: Fri, 20 May 88 13:29:58 MDT
Subject: Re: issue EVAL-WHEN-NON-TOP-LEVEL
To: Rob.MacLachlan@wb1.cs.cmu.edu
> Date: Fri, 20 May 88 14:59:13 EDT
> From: Rob.MacLachlan@WB1.CS.CMU.EDU
>
> In this form, I believe (FOO) would never be evaluated in
> any context, which is definitely an incompatible change:
> (eval-when (compile)
> (eval-when (compile)
> (foo)))
Yes, you are correct that under the current proposal, (foo) would never
be evaluated. I do not think it is "definitely" an incompatible change,
however. The current wording in CLtL seems to leave this behavior
unspecified and I don't know what the original intention was.
I guess CLTL does leave that one hanging. But this deserves at least some
compatibility/current practice note in the proposal. This is incompatible
with at least our implementation.
The behavior you suggest seems non-intuitive to me. The whole theory
behind EVAL-WHEN is that there are these independently composable
situations, any combination of which may be specified. Specifying a
particular situation has a particular effect, independently of what other
situations are present. In particular, specifying the COMPILE situation
guarantees that the body will be evaluated at compile time.
Of course, as I have pointed out before, the theory behind EVAL-WHEN is
wrong, so it isn't clear how upset we should be about mental models of
EVAL-WHEN being violated.
Rob
∂21-May-88 0456 CL-Compiler-mailer issue EVAL-WHEN-NON-TOP-LEVEL
Received: from labrea.stanford.edu by SAIL.Stanford.EDU with TCP; 21 May 88 04:56:45 PDT
Received: by labrea.stanford.edu; Sat, 21 May 88 04:57:03 PDT
Received: from bhopal.lucid.com by edsel id AA19600g; Sat, 21 May 88 04:39:11 PDT
Received: by bhopal id AA08170g; Sat, 21 May 88 04:42:51 PDT
Date: Sat, 21 May 88 04:42:51 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
Message-Id: <8805211142.AA08170@bhopal.lucid.com>
To: labrea!vanroggen%aitg.decnet@hudson.dec.com
Cc: cl-compiler@sail.stanford.edu, vanroggen@sail.stanford.edu
In-Reply-To: "AITG::VANROGGEN"'s message of 20 May 88 11:19:00 EDT <8805201736.AA15806@edsel.lucid.com>
Subject: issue EVAL-WHEN-NON-TOP-LEVEL
re: A major nit (!?): Isn't there a cleanup proposal to disallow lexically
binding special-forms in FLET, LABELS, and MACROLET? If so, your
EVAL-WHEN macro is doing a no-no. You might want to change the statement
from "suggested implementation technique" to "implemented as if".
This proposal changes EVAL-WHEN from being a special-form into being a
MACRO [that expands into some readily-understandable(?) code]. Thus it
wouldn't be subject to the no-shadowing-of-special-forms rule.
-- JonL --
∂21-May-88 1200 CL-Compiler-mailer Re: issue EVAL-WHEN-NON-TOP-LEVEL
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 21 May 88 12:00:24 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA28310; Sat, 21 May 88 10:11:26 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805211611.AA28310@cs.utah.edu>
Date: Sat, 21 May 88 10:11:25 MDT
Subject: Re: issue EVAL-WHEN-NON-TOP-LEVEL
To: Jon L White <edsel!jonl@labrea.stanford.edu>
Cc: labrea!vanroggen%aitg.decnet@hudson.dec.com, cl-compiler@sail.stanford.edu,
vanroggen@sail.stanford.edu
In-Reply-To: Jon L White <edsel!jonl@labrea.stanford.edu>, Sat, 21 May 88 04:42:51 PDT
> Date: Sat, 21 May 88 04:42:51 PDT
> From: Jon L White <edsel!jonl@labrea.stanford.edu>
>
> This proposal changes EVAL-WHEN from being a special-form into being a
> MACRO [that expands into some readily-understandable(?) code]. Thus it
> wouldn't be subject to the no-shadowing-of-special-forms rule.
Well, it doesn't go quite that far. In the new, revised version of the
proposal, I was going to say that EVAL-WHEN behaves *as if* it were
implemented as a macro. Changing its "official" status from special form
to macro is a somewhat larger step.
I can think of cases where user code would still want to think of it as
a special form, particularly if we don't decide to make the *compiling-p*
variable public. For instance, if you're trying to implement some kind
of a code-walking preprocessor, you would probably want it to leave the
EVAL-WHENs in place since the context in which the preprocessor executes
may not be the same as the context in which the code it produces is to
be processed.
I will bow to the wishes of the subcommittee on this issue. I do think
we need to make a decision one way or the other and include the rationale
in the proposal, because somebody else is bound to bring it up later on.
-Sandra
-------
∂23-May-88 1124 CL-Compiler-mailer issue DEFINING-MACROS-NON-TOP-LEVEL
Received: from hudson.dec.com by SAIL.Stanford.EDU with TCP; 23 May 88 11:24:38 PDT
Date: 23 May 88 14:06:00 EDT
From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Subject: issue DEFINING-MACROS-NON-TOP-LEVEL
To: "cl-compiler" <cl-compiler@sail.stanford.edu>
cc: vanroggen
Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
This one looks pretty good too.
Remove the
language on p. 66 of CLtL which states that the compiler is not
required to recognize defining macros at other than top-level.
Except this is still true:
(let ((x (f)))
(defmacro m (y) `(+ ,x ,y)))
...
(defun g (...)
... (m ...) ...)
and inside G the use of M is an error because it isn't guaranteed to be
recognized as a call to a macro. As you indicate later, using EVAL-WHEN
would provide a means of avoiding this problem.
Another example of this restriction:
(defun f (...)
...
(defstruct ship length ...)
... (ship-length ...) ...
...)
The use of SHIP-LENGTH in F is an error.
It would be worthwhile to remind readers that the names/bindings are
still global. Thus in the defstruct example above,
there is not guaranteed to be a SHIP type until after F is called, there
might not be any SHIP-xxx functions until after F is called, and
all the names created by the DEFSTRUCT will be global.
---Walter
------
∂24-May-88 1236 CL-Compiler-mailer new versions of proposals
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 24 May 88 12:35:59 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA04797; Tue, 24 May 88 13:36:10 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805241936.AA04797@cs.utah.edu>
Date: Tue, 24 May 88 13:36:09 MDT
Subject: new versions of proposals
To: cl-compiler@sail.stanford.edu
Coming up shortly (at long last) will be the revised versions of the
eval-when and defining macro proposals. I apologize for taking so long;
the machine I was editing them on died a horrible death Friday afternoon
and is still in pieces, sigh. Anyway, I have tried to clean up the
language and resolve some ambiguities that had previously gone
unnoticed.
So far I have received comments only from Walter about the third
proposal (about allowing defining macros in other than top-level
locations). Does this mean everybody else is perfectly happy with it as
it stands?
-Sandra
-------
∂24-May-88 1236 CL-Compiler-mailer new, improved EVAL-WHEN proposal
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 24 May 88 12:36:28 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA04812; Tue, 24 May 88 13:36:39 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805241936.AA04812@cs.utah.edu>
Date: Tue, 24 May 88 13:36:37 MDT
Subject: new, improved EVAL-WHEN proposal
To: cl-compiler@sail.stanford.edu
Issue: EVAL-WHEN-NON-TOP-LEVEL
References: CLtL p. 69-70
Issue DEFINING-MACROS-NON-TOP-LEVEL
Category: CLARIFICATION, ENHANCEMENT
Edit History: 6-May-88, V1 by Sandra Loosemore
Problem Description:
The current description of how the compiler should handle EVAL-WHEN
only makes sense when it appears as a top-level form in the file being
compiled. Other proposals being considered by the compiler cleanup
committee require that we clarify how the compiler should process
EVAL-WHENs appearing at non-top-level, such as within LET or FUNCTION
special forms.
Proposal: EVAL-WHEN-NON-TOP-LEVEL:CLARIFY
In this proposal, we view EVAL-WHEN as a macro which expands into a
PROGN containing the body of the EVAL-WHEN when the context in which it
is expanded matches one of the situations listed, or NIL otherwise.
However, it is explicitly *not* proposed that EVAL-WHEN's status as
a special form be changed.
The EVAL situation corresponds to the normal processing of the
interpreter. If EVAL is specified, the interpreter evaluates each
form in the body of the EVAL-WHEN as an implicit PROGN, using the
current lexical environment. If the EVAL situation is not specified,
then the interpreter must return NIL as the value of the EVAL-WHEN
form, without evaluating the body.
The LOAD situation corresponds to the normal processing of the
compiler. If LOAD is specified, the compiler treats the EVAL-WHEN as
a PROGN and compiles the body in the normal way in the appropriate
lexical environment. Otherwise, the form is equivalent to specifying
a constant value of NIL. (The name LOAD is something of a misnomer,
because ``evaluation'' of the body happens not at LOAD time, but when
the EVAL-WHEN form would normally be ``evaluated''. For example, if
an EVAL-WHEN form appears in the body of a DEFUN, it is ``evaluated''
when that function is called.)
The COMPILE situation is a special case; it indicates that the
compiler itself should evaluate the body of the EVAL-WHEN form as an
implicit PROGN in the null lexical environment. During the
evaluation, if a nested EVAL-WHEN appears in the body, the interpreter
follows its usual rule of checking only whether or not the EVAL
situation is specified to decide whether or not the body of the nested
EVAL-WHEN should be processed.
If both the COMPILE and LOAD situations are specified, the compiler
first performs the evaluation for the COMPILE situation. Then, the
normal processing for the LOAD situation takes place, except that the
compile-time evaluation of nested (EVAL-WHEN (COMPILE) ...) forms in
the body is suppressed, preventing repeated evaluations of subforms.
(EVAL-WHEN (COMPILE) ...) should be used with caution in non-top-level
situations. For example, if the following appears as a top level form
in a file being compiled
(let ((x (some-hairy-computation)))
(eval-when (eval compile load) (print x)))
the variable X will be treated as special during the compile-time
evaluation, and the value printed will be its symbol-value. To
guarantee consistency between compile-time evaluation and the normal
processing, one should wrap the entire top-level form in an EVAL-WHEN,
as follows:
(eval-when (eval-compile load)
(let ((x (some-hairy-computation)))
(print x)))
Rationale:
The behavior of top-level EVAL-WHENs as specified in this proposal
remains almost identical to that specified in CLtL. The major
addition is specifying the lexical environment in which non-top-level
EVAL-WHENs are processed. It is clear that the COMPILE situation must
always be processed in the null lexical environment, since the actual
lexical environment is not available at compile time. Having the EVAL
and LOAD situations evaluate in the proper environment leads to
differing semantics, but it appears to be the behavior that most
people expect, and it is also the easiest to implement.
Suppression of COMPILE evaluations in nested EVAL-WHENs is necessary
to achieve certain desirable behaviors, such as the macro example in
section 4 of the DEFINING-MACROS-NON-TOP-LEVEL proposal.
Although viewing EVAL-WHEN as a macro is useful for purposes of
explanation, user code is likely to want to continue to treat EVAL-WHEN
as a special form. For example, a preprocessor that performs a code
walk should leave EVAL-WHENs intact, since the context in which the
preprocessor runs may not be the same as the context in which the code
it produces runs.
Current Practice:
Cost to implementors:
Probably fairly minor in most implementations.
As an implementation technique, we suggest implementing EVAL-WHEN as a
macro which uses a state variable to keep track of the current context.
A sample implementation might look something like:
(defvar *compiling-p* nil "Are we compiling or interpreting?")
(defmacro eval-when (situations &body body)
(cond
;; If the COMPILE situation applies, evaluate the body now
;; and also see if we need to do the LOAD situation too.
;; If so, shadow the definition of EVAL-WHEN to make it
;; ignore nested compile-time evaluation requests, and
;; return the body.
((and *compiling-p* (member 'compile situations))
(eval `(progn ,@body))
(if (member 'load situations)
`(macrolet ((eval-when (situations &body body)
(if (member 'load situations)
`(progn ,@body)
'nil)))
,@body)
'nil))
;; If either the EVAL or LOAD situation applies, return a PROGN.
((if *compiling-p*
(member 'load situations)
(member 'eval situations))
`(progn ,@body))
;; Otherwise no situation applies, so just return NIL.
(t
'nil)))
;;; Eval must bind *compiling-p* to NIL.
(defun eval (form)
(let ((*compiling-p* nil))
:
))
;;; Compile and Compile-file must bind *compiling-p* to a non-nil value.
(defun compile (name &optional definition)
(let ((*compiling-p* t))
:
))
(defun compile-file (input-pathname &key output-file)
(let ((*compiling-p* t))
:
))
Cost to users:
Since CLtL does not currently specify what the meaning of EVAL-WHEN
forms at non-top-level is, existing code which depends on their use is
already nonportable. Preventing repeated evaluations of subforms when
EVAL-WHENs are nested is unlikely to cause any serious compatibility
problems, since the current model would already result in only a
single evaluation in the case when the code is processed
interpretively.
There are also some situations concerning nested top-level occurences
of EVAL-WHEN that CLtL does not completely specify, to which this
proposal does assign a specific interpretation. For example, CLtL is
unclear on whether or not (FOO) would ever be called, while in the
current proposal it would definitely not be called:
(eval-when (compile)
(eval-when (compile)
(foo)))
Benefits:
Clarifying the meaning of EVAL-WHEN allows the behavior of defining
macros such as DEFMACRO to be specified in terms of EVAL-WHEN. As a
side effect, it would then become meaningful for defining macros to
appear at other than top-level.
Discussion:
This proposal reflects what appears to be the consensus of the
compiler cleanup committee on this issue.
-------
∂24-May-88 1237 CL-Compiler-mailer new, improved defining macros proposal
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 24 May 88 12:36:55 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA04849; Tue, 24 May 88 13:37:06 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805241937.AA04849@cs.utah.edu>
Date: Tue, 24 May 88 13:37:06 MDT
Subject: new, improved defining macros proposal
To: cl-compiler@sail.stanford.edu
Issue: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
References: CLtL pages 66-70, 143
Category: CLARIFICATION
Edit history: V1, 07 Oct 1987 Sandra Loosemore
V2, 15 Oct 1987 Sandra Loosemore
V3, 15 Jan 1988 Sandra Loosemore
V4, 06 May 1988 Sandra Loosemore
V5, 20 May 1988 Sandra Loosemore
Problem Description:
Standard programming practices assume that, when calls to defining
macros such as DEFMACRO and DEFVAR are processed by COMPILE-FILE,
certain side-effects occur that affect how subsequent forms in the
file are compiled. However, these side-effects are not mentioned in
CLtL, except for a passing mention that macro definitions must be
``seen'' by the compiler before it can compile calls to those macros
correctly. In order to write portable programs, users must know
exactly which defining macros have compile-time side-effects and what
those side-effects are.
Inter-file compilation dependencies are distinct from, and not
addressed by, this issue.
Proposal: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
(1) Clarify that defining macros such as DEFMACRO or DEFVAR, appearing
within a file being processed by COMPILE-FILE, normally have
compile-time side effects which affect how subsequent forms in the
same file are compiled. A convenient model for explaining how these
side effects happen is that the defining macro expands into one or
more EVAL-WHEN forms, and that the calls which cause the compile-time
side effects to happen appear in the body of an (EVAL-WHEN (COMPILE)
...) form. This is also the recommended implementation technique.
(2) The affected defining macros and their specific side effects are
as follows:
DEFTYPE: The body of a DEFTYPE form must be evaluable at compile time.
If the expansion of a DEFTYPE'd type specifier is also a valid type
specifier at compile time, then the DEFTYPE'd type specifier is also
considered to be fully defined at compile time and must be recognized
within subsequent type declarations.
DEFMACRO, DEFINE-MODIFY-MACRO: Macro definitions must be stored at compile
time, so that occurences of the macro later on in the file will be expanded
correctly. The body of the macro (but not necesarily its expansion) must
be evaluable at compile time.
DEFUN: An implementation may choose to store information about the
function for the purposes of compile-time error-checking (such as
checking the number of arguments on calls), or to enable the function
to be expanded inline. Portable code should not rely on DEFUN making
the function definition available at compile time.
DEFVAR, DEFPARAMETER: The compiler must recognize that the variables
named by these forms have been proclaimed special. The initial value
form must not be evaluated at compile time.
DEFCONSTANT: An implementation may choose to store information about
the variable for the purposes of compile-time error-checking, such as
checking for rebinding of or assignment to the variable. The initial
value form must not be evaluated at compile time. (If the initial
value is a constant, however, an implementation is allowed to
substitute the constant value for references to the named constant
during subsequent compilation.)
DEFSETF, DEFINE-SETF-METHOD: SETF methods must be available during the
expansion of calls to SETF later on in the file. The body of
DEFINE-SETF-METHOD and the complex form of DEFSETF must be evaluable
at compile time, although the expansions need not be.
DEFSTRUCT: The structure type name must be recognized as a valid type name
in declarations, as for DEFTYPE. The structure slot accessors must be made
known to SETF. In addition, further DEFSTRUCT definitions should be able
to :INCLUDE a structure type defined earlier in the file being compiled.
The functions which DEFSTRUCT generates, and the #S reader syntax, may or
may not be available at compile time.
(3) The compile-time side effects may cause information about the
definition to be stored differently than if the defining macro had
been processed in the "normal" way (either interpretively or by loading
the compiled file).
In particular, the information stored by the defining macros at
compile time may or may not be available to the interpreter (either
during or after compilation), or during subsequent calls to COMPILE or
COMPILE-FILE. For example, the following code is nonportable because
it assumes that the compiler stores the macro definition of FOO where
it is available to the interpreter:
(defmacro foo (x) `(car ,x))
(eval-when (eval compile load)
(print (foo '(a b c))))
A portable way to do the same thing would be to include the macro definition
inside the EVAL-WHEN:
(eval-when (eval compile load)
(defmacro foo (x) `(car ,x))
(print (foo '(a b c))))
Rationale:
The proposal reflects standard programming practices. The primary
purpose of the proposal is to make an explicit statement that CL
supports the behavior that most programmers expect and many
implementations already provide.
Current Practice:
Many (probably most) Common Lisp implementations, including VaxLisp
and Lucid Lisp, are already largely in conformance.
In VaxLisp, macro definitions that occur as a side effect of compiling
a DEFMACRO form are available to the compiler (even on subsequent calls
to COMPILE or COMPILE-FILE), but are not available to the interpreter
(even within the file being compiled).
Kyoto Common Lisp is a notable offender. By default, KCL evaluates *all*
top level forms as they are compiled, which is clearly in violation of the
behavior specified on p 69-70 of CLtL. There is a flag to disable the
compile-time evaluation, but then macros such as DEFMACRO, DEFVAR, etc. do
not make their definitions available at compile-time either.
Cost to implementors:
Making the defining macros expand into EVAL-WHENs to store the required
information is a simple and recommended implementation technique. The
intent of the proposal is specifically not to require the compiler to
have special knowledge about each of these macros.
Cost to users:
Since CLtL does not specify whether and what compile-time side-effects
happen, any user code which relies on them is, strictly speaking,
nonportable. In practice, however, most programmers already expect
the behavior described in this proposal and will not find it to be
an incompatible change.
Benefits:
Adoption of the proposal will provide more definite guidelines on how to
write programs that will compile correctly under all CL implementations.
Discussion:
Reaction to an earlier version of this proposal on the CL mailing list was
overwhelmingly positive.
It has been suggested that this proposal should also include PROCLAIM.
However, since PROCLAIM is not a macro, its compile-time side effects
cannot be handled using the EVAL-WHEN mechanism. A separate proposal
seems more appropriate.
There has also been a suggestion that DEFCONSTANT should always
evaluate the value provided. The behavior specified in this proposal
makes DEFCONSTANT similar to DEFVAR and DEFPARAMETER, while allowing
the user to explicitly ask for compile-time evaluation using the #. read
macro.
Item (3) allows for significant deviations between implementations.
While there is some sentiment to the effect that the compiler should
store definitions in a manner identical to that of the interpreter,
other people believe strongly that compiler side-effects should be
completely invisible to the interpreter. The author is of the opinion
that since this is a controversial issue, further attempts to restrict
this behavior should be considered as separate proposals.
-------
∂24-May-88 1251 CL-Compiler-mailer Re: issue DEFINING-MACROS-NON-TOP-LEVEL
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 24 May 88 12:50:53 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA05361; Tue, 24 May 88 13:50:14 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805241950.AA05361@cs.utah.edu>
Date: Tue, 24 May 88 13:50:13 MDT
Subject: Re: issue DEFINING-MACROS-NON-TOP-LEVEL
To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Cc: "cl-compiler" <cl-compiler@sail.stanford.edu>
In-Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>, 23 May 88 14:06:00 EDT
> Date: 23 May 88 14:06:00 EDT
> From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
>
> Except this is still true:
> (let ((x (f)))
> (defmacro m (y) `(+ ,x ,y)))
> ...
> (defun g (...)
> ... (m ...) ...)
> and inside G the use of M is an error because it isn't guaranteed to be
> recognized as a call to a macro.
I don't think this follows from our model of how the defining macros
do their thing at compile time, and how EVAL-WHEN works at
non-top-level. The DEFMACRO presumably would expand into an (EVAL-WHEN
(COMPILE) ...) to store the macro definition for the compiler, and as
long as the compiler processes this before it runs across any calls to
the macro, this example would be OK (that is, if it were not for the
problem of the macro function getting defined in the wrong lexical
environment).
If you want the defining macros to have their compile-time side-effects
occur only if they appear at top-level, I think we have to come up with
some other model to explain how this happens (other than saying that
they expand into EVAL-WHENs). Do we really want to do that?
-Sandra
-------
∂24-May-88 1623 CL-Compiler-mailer new, improved defining macros proposal
Received: from EDDIE.MIT.EDU by SAIL.Stanford.EDU with TCP; 24 May 88 16:22:56 PDT
Received: by EDDIE.MIT.EDU with UUCP with smail2.5 with sendmail-5.45/4.7 id <AA19899@EDDIE.MIT.EDU>; Tue, 24 May 88 19:20:05 EDT
Received: by spt.entity.com (smail2.5); 24 May 88 18:17:07 EDT (Tue)
To: sandra@cs.utah.edu
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: Sandra J Loosemore's message of Tue, 24 May 88 13:37:06 MDT <8805241937.AA04849@cs.utah.edu>
Subject: new, improved defining macros proposal
Message-Id: <8805241817.AA22314@spt.entity.com>
Date: 24 May 88 18:17:07 EDT (Tue)
From: gz@spt.entity.com (Gail Zacharias)
I just started receiving this mailing list, so my apologies if this has been
discussed before.
DEFCONSTANT: ... (If the initial
value is a constant, however, an implementation is allowed to
substitute the constant value for references to the named constant
during subsequent compilation.)
I have a problem with this. The compiler shouldn't have licence to substitute
for the variable without fully implementing the semantics of DEFCONSTANT.
In particular, under this proposal, would the DEFCONSTANT's with constant
initial values be "evaluable at compile time" in the sense used in the
description of DEFMACRO? I.e. would the following work?
(DEFCONSTANT FOO 'FOO)
(DEFMACRO FOO () `',FOO)
(DEFVAR *FOO* (FOO))
In addition, the distinction between constant/non-constant initial value is
artificial and potentially ambiguous in the face of differing constant-folding
capabilities. Consider
(DEFCONSTANT FOO 17)
(DEFCONSTANT BAR (ASH 1 FOO))
Are compilers allowed to substitute for BAR?
I think toplevel DEFCONSTANT should either be treated like DEFMACRO (i.e.
implicitly compile-time: initial value "must be evaluable at compile time" and
the binding must be made available to other compile-time code) or like
DEFVAR/DEFPARAMETER (implicitly load-time: compiler recognizes the variable as
special, but it is not allowed to substitute the value). I don't have a
strong preference either way (since you can always get "the other" semantics
via eval-when), but I don't like the proposed mixture of the two.
∂25-May-88 0809 CL-Compiler-mailer Re: Issue: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS (version 5)
Received: from hudson.dec.com by SAIL.Stanford.EDU with TCP; 25 May 88 08:09:31 PDT
Date: 25 May 88 11:06:00 EDT
From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Subject: Re: Issue: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS (version 5)
To: "cl-compiler" <cl-compiler@sail.stanford.edu>
cc: vanroggen
Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
I agree with the proposal in its treating the initial value form of
DEFCONSTANT just like those of DEFVAR and DEFPARAMETER in that that form
must not be evaluated at compile time. (Of course, DEFCONSTANT, just like
the others, may macroexpand into code that evaluates at compile-time.)
However, to answer the concerns of compiler implementors not being able
to make certain optimizations, it's quite permissible for compilers to
"evaluate" constants, both literals such as 3.4 and expressions such as
(ASH 3 7) or even (ASH FOO BAR) if both FOO and BAR were previously
defined DEFCONSTANTS with constant values. The point is that if the
constant value depends on its run-time environment in any way, the
compiler can't try to do "constant folding" too early unless it can prove
there won't be any difference.
There's a separate issue here regarding substitution of constants, I think,
in whether it's permissible for (DEFCONSTANT FOO "abc") and a later use of
FOO to "copy" the string value. I'd change the wording about substitution
of constants to mention that that's a separate issue for clean-up.
BTW, in the next-to-last paragraph, using "#." is also the wrong time--
since read-time might well be too early. It's best to recommend either
that or EVAL-WHEN as needed.
---Walter
------
∂25-May-88 0926 CL-Compiler-mailer Re: new, improved defining macros proposal
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 25 May 88 09:24:41 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA04830; Wed, 25 May 88 10:24:32 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8805251624.AA04830@cs.utah.edu>
Date: Wed, 25 May 88 10:24:31 MDT
Subject: Re: new, improved defining macros proposal
To: gz@spt.entity.com (Gail Zacharias)
Cc: cl-compiler@sail.stanford.edu
In-Reply-To: gz@spt.entity.com (Gail Zacharias), 24 May 88 18:17:07 EDT (Tue)
Sigh, this issue just won't go away.
What one would normally expect DEFCONSTANT to do is to setq the symbol
and then somehow mark it as being constant, so that it can't be setq'ed
again. At compile-time, if the value-form is not evaluable, you
obviously can't setq it yet. I agree it would be silly to specify
that the setq'ing happens at compile-time in some cases but not in
others, and that was certainly not what I had in mind.
The intention was that *if* the compiler does substitution of symbolic
constants with their values *and* it can determine the value of the
symbolic constant at compile-time, *then* the compiler can assume
that the value of the constant at run-time is the same as what it sees
at compile-time and go ahead and make a substitution for it. I would
assume that if an implementation is sophisticated enough to do all of
this, it would be able to store the information about the constant value
using some other mechanism besides setq'ing the symbol at compile-time.
I can try rewording this part of the proposal yet again. I think the
main points are:
(1) the compiler should know that the symbol is a constant so it will
not complain when it sees references to it as an unbound variable, and
possibly so it will complain when it sees attempts to setq or bind the
symbol.
(2) neither the evaluation of the value-form or the setq'ing of the
symbol may happen at compile-time (analagous to DEFVAR and DEFPARAMETER)
(3) if the value-form can be evaluated at compile-time, the compiler may
assume that the constant will have the same value at run-time.
-Sandra
-------
∂27-May-88 0828 CL-Compiler-mailer Re: Issue: EVAL-WHEN-NON-TOP-LEVEL
Received: from hudson.dec.com by SAIL.Stanford.EDU with TCP; 27 May 88 08:28:08 PDT
Date: 27 May 88 11:15:00 EDT
From: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
Subject: Re: Issue: EVAL-WHEN-NON-TOP-LEVEL
To: "cl-compiler" <cl-compiler@sail.stanford.edu>
cc: vanroggen
Reply-To: "AITG::VANROGGEN" <vanroggen%aitg.decnet@hudson.dec.com>
There really isn't enough consideration of what happens when the
EVAL-WHEN isn't a top-level, and what following expressions may
depend on from what was inside a non-top-level EVAL-WHEN.
The problem is what order expressions may get "processed", particularly
by code-walkers such as compilers.
Here's a simple example which assumes the DEFMACRO expands into an
(EVAL-WHEN ...) to tell everyone who cares (particularly the compiler at
compile time) that M is a macro.
(let ...
(defmacro m ...)
(m ...))
But the body of the LET is equivalent to
(let ...
(flet ((rest () (m ...)))
(defmacro m ...)
(rest)))
which isn't going to work.
The easiest solution is to assume that one cannot depend on the effects
of the EVAL-WHEN at compile time until the next top-level form.
---Walter
------
∂09-Jun-88 0921 CL-Compiler-mailer Compiler Subcommittee meeting
Received: from ucbarpa.Berkeley.EDU by SAIL.Stanford.EDU with TCP; 9 Jun 88 09:21:34 PDT
Received: by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA01037; Thu, 9 Jun 88 09:20:22 PDT
Received: by franz (3.2/3.14)
id AA02004; Thu, 9 Jun 88 08:02:11 PDT
Received: by feast (5.5/3.14)
id AA00828; Thu, 9 Jun 88 10:32:54 EDT
Date: Thu, 9 Jun 88 10:32:54 EDT
From: franz!feast!smh@ucbarpa.Berkeley.EDU (Steven M. Haflich)
Message-Id: <8806091432.AA00828@feast>
To: franz!sail.stanford.edu!cl-compiler
Subject: Compiler Subcommittee meeting
Owing to the difficulty in scheduling conference rooms at Symbolics in
the evening, our subcommittee will meet at:
Tuesday, June 14, 7:30 PM
Gigamos
675 Massachusetts Avenue
Cambridge MA
Gigamos is on the 7th floor of a large office building which is a mere
few steps from the MBTA Central Square Red Line stop, or about a 20
minute walk from Harvard Square, Symbolics, or MIT. There is a
security guard who should allow you to sign in by mentioning Gigamos,
but if there is any difficulty, call Gigamos from the lobby at
876-6819 and ask for me.
Please RSVP so we can know who's coming and when it's safe to start.
If anyone would like to meet for dinner beforehand (or afterhand) that
would be just dandy. There are a multitude of superb ethnic
establishments in the immediate neighborhood.
∂09-Jun-88 1219 CL-Compiler-mailer Compiler Subcommittee meeting
Received: from ucbarpa.Berkeley.EDU by SAIL.Stanford.EDU with TCP; 9 Jun 88 12:19:27 PDT
Received: by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA04525; Thu, 9 Jun 88 12:18:16 PDT
Received: by franz (3.2/3.14)
id AA02522; Thu, 9 Jun 88 11:24:12 PDT
Received: from TI.COM by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA02196; Thu, 9 Jun 88 10:29:10 PDT
Received: by ti.com id AA04276; Thu, 9 Jun 88 12:28:03 CDT
Received: from mips by tilde id AA15746; Thu, 9 Jun 88 12:25:12 CDT
Received: by mips id AA09228; Thu, 9 Jun 88 12:25:03 CDT
Date: Thu, 9 Jun 88 12:25:03 CDT
From: David Bartley <franz!ucbarpa!mips.csc.ti.com!bartley@ucbarpa.Berkeley.EDU>
Message-Id: <8806091725.AA09228@mips>
To: franz!feast!smh
Cc: franz!sail.stanford.edu!cl-compiler
In-Reply-To: "Steven M. Haflich"'s message of Thu, 9 Jun 88 10:32:54 EDT <8806091432.AA00828@feast>
Subject: Compiler Subcommittee meeting
> Please RSVP so we can know who's coming and when it's safe to start.
I expect to make it.
∂09-Jun-88 1346 CL-Compiler-mailer Re: Compiler Subcommittee meeting
Received: from NSS.Cs.Ucl.AC.UK by SAIL.Stanford.EDU with TCP; 9 Jun 88 13:41:27 PDT
Received: from aiai.edinburgh.ac.uk by NSS.Cs.Ucl.AC.UK via Janet with NIFTP
id aa09118; 9 Jun 88 21:31 BST
From: Jeff Dalton <jeff%aiai.edinburgh.ac.uk@NSS.Cs.Ucl.AC.UK>
Date: Thu, 9 Jun 88 21:31:12 BST
Message-Id: <17148.8806092031@aiai.ed.ac.uk>
To: cl-compiler@sail.stanford.edu
Subject: Re: Compiler Subcommittee meeting
> Please RSVP so we can know who's coming and when it's safe to start.
I'd mail to you directly, but there's just no hope of figuring
out what magic incantations are necessary to reach
edu.berkeley.ucbarpa!franz!feast!smh
from here.
> There are a multitude of superb ethnic establishments
Good idea.
Jeff Dalton, JANET: J.Dalton@uk.ac.ed
AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton
∂09-Jun-88 1415 CL-Compiler-mailer (another) revised version of the defining macros proposal
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 Jun 88 14:14:47 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA12037; Thu, 9 Jun 88 14:41:41 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8806092041.AA12037@cs.utah.edu>
Date: Thu, 9 Jun 88 14:41:39 MDT
Subject: (another) revised version of the defining macros proposal
To: cl-compiler@sail.stanford.edu
Here is yet another revision to the defining macros proposal. The only
thing that has changed is the wording of the DEFCONSTANT section. I hope
that this time I have at least managed to make the language concise enough
so that we can agree on what it says, even if we don't all agree *with*
what it says.
-Sandra
Issue: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
References: CLtL pages 66-70, 143
Category: CLARIFICATION
Edit history: V1, 07 Oct 1987 Sandra Loosemore
V2, 15 Oct 1987 Sandra Loosemore
V3, 15 Jan 1988 Sandra Loosemore
V4, 06 May 1988 Sandra Loosemore
V5, 20 May 1988 Sandra Loosemore
V6, 09 Jun 1988 Sandra Loosemore
Problem Description:
Standard programming practices assume that, when calls to defining
macros such as DEFMACRO and DEFVAR are processed by COMPILE-FILE,
certain side-effects occur that affect how subsequent forms in the
file are compiled. However, these side-effects are not mentioned in
CLtL, except for a passing mention that macro definitions must be
``seen'' by the compiler before it can compile calls to those macros
correctly. In order to write portable programs, users must know
exactly which defining macros have compile-time side-effects and what
those side-effects are.
Inter-file compilation dependencies are distinct from, and not
addressed by, this issue.
Proposal: COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
(1) Clarify that defining macros such as DEFMACRO or DEFVAR, appearing
within a file being processed by COMPILE-FILE, normally have
compile-time side effects which affect how subsequent forms in the
same file are compiled. A convenient model for explaining how these
side effects happen is that the defining macro expands into one or
more EVAL-WHEN forms, and that the calls which cause the compile-time
side effects to happen appear in the body of an (EVAL-WHEN (COMPILE)
...) form. This is also the recommended implementation technique.
(2) The affected defining macros and their specific side effects are
as follows:
DEFTYPE: The body of a DEFTYPE form must be evaluable at compile time.
If the expansion of a DEFTYPE'd type specifier is also a valid type
specifier at compile time, then the DEFTYPE'd type specifier is also
considered to be fully defined at compile time and must be recognized
within subsequent type declarations.
DEFMACRO, DEFINE-MODIFY-MACRO: Macro definitions must be stored at compile
time, so that occurences of the macro later on in the file will be expanded
correctly. The body of the macro (but not necesarily its expansion) must
be evaluable at compile time.
DEFUN: An implementation may choose to store information about the
function for the purposes of compile-time error-checking (such as
checking the number of arguments on calls), or to enable the function
to be expanded inline. Portable code should not rely on DEFUN making
the function definition available at compile time.
DEFVAR, DEFPARAMETER: The compiler must recognize that the variables
named by these forms have been proclaimed special. The initial value
form must not be evaluated at compile time.
DEFCONSTANT: The compiler must recognize the symbol as being constant
(for example, to suppress warnings about references to the symbolic
constant as an unbound variable or to enable warnings about binding or
SETQ'ing the constant in the code being compiled). Neither evaluation
of the value-form or SETQ'ing of the symbol may occur at compile-time.
However, if the (unevaluated) value-form is CONSTANTP, the compiler is
allowed to build assumptions about the value of the constant into
programs being compiled, as described on p. 68-69 of CLtL.
DEFSETF, DEFINE-SETF-METHOD: SETF methods must be available during the
expansion of calls to SETF later on in the file. The body of
DEFINE-SETF-METHOD and the complex form of DEFSETF must be evaluable
at compile time, although the expansions need not be.
DEFSTRUCT: The structure type name must be recognized as a valid type name
in declarations, as for DEFTYPE. The structure slot accessors must be made
known to SETF. In addition, further DEFSTRUCT definitions should be able
to :INCLUDE a structure type defined earlier in the file being compiled.
The functions which DEFSTRUCT generates, and the #S reader syntax, may or
may not be available at compile time.
(3) The compile-time side effects may cause information about the
definition to be stored differently than if the defining macro had
been processed in the "normal" way (either interpretively or by loading
the compiled file).
In particular, the information stored by the defining macros at
compile time may or may not be available to the interpreter (either
during or after compilation), or during subsequent calls to COMPILE or
COMPILE-FILE. For example, the following code is nonportable because
it assumes that the compiler stores the macro definition of FOO where
it is available to the interpreter:
(defmacro foo (x) `(car ,x))
(eval-when (eval compile load)
(print (foo '(a b c))))
A portable way to do the same thing would be to include the macro definition
inside the EVAL-WHEN:
(eval-when (eval compile load)
(defmacro foo (x) `(car ,x))
(print (foo '(a b c))))
Rationale:
The proposal reflects standard programming practices. The primary
purpose of the proposal is to make an explicit statement that CL
supports the behavior that most programmers expect and many
implementations already provide.
Current Practice:
Many (probably most) Common Lisp implementations, including VaxLisp
and Lucid Lisp, are already largely in conformance.
In VaxLisp, macro definitions that occur as a side effect of compiling
a DEFMACRO form are available to the compiler (even on subsequent calls
to COMPILE or COMPILE-FILE), but are not available to the interpreter
(even within the file being compiled).
Kyoto Common Lisp is a notable offender. By default, KCL evaluates *all*
top level forms as they are compiled, which is clearly in violation of the
behavior specified on p 69-70 of CLtL. There is a flag to disable the
compile-time evaluation, but then macros such as DEFMACRO, DEFVAR, etc. do
not make their definitions available at compile-time either.
Cost to implementors:
Making the defining macros expand into EVAL-WHENs to store the required
information is a simple and recommended implementation technique. The
intent of the proposal is specifically not to require the compiler to
have special knowledge about each of these macros.
Cost to users:
Since CLtL does not specify whether and what compile-time side-effects
happen, any user code which relies on them is, strictly speaking,
nonportable. In practice, however, most programmers already expect
the behavior described in this proposal and will not find it to be
an incompatible change.
Benefits:
Adoption of the proposal will provide more definite guidelines on how to
write programs that will compile correctly under all CL implementations.
Discussion:
Reaction to an earlier version of this proposal on the CL mailing list was
overwhelmingly positive.
It has been suggested that this proposal should also include PROCLAIM.
However, since PROCLAIM is not a macro, its compile-time side effects
cannot be handled using the EVAL-WHEN mechanism. A separate proposal
seems more appropriate.
There has also been a suggestion that DEFCONSTANT should always
evaluate the value provided. The behavior specified in this proposal
makes DEFCONSTANT similar to DEFVAR and DEFPARAMETER, while allowing
the user to explicitly ask for compile-time evaluation using the #. read
macro.
Item (3) allows for significant deviations between implementations.
While there is some sentiment to the effect that the compiler should
store definitions in a manner identical to that of the interpreter,
other people believe strongly that compiler side-effects should be
completely invisible to the interpreter. The author is of the opinion
that since this is a controversial issue, further attempts to restrict
this behavior should be considered as separate proposals.
-------
∂09-Jun-88 1414 CL-Compiler-mailer (another) new version of the non-top-level defining macros proposal
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 Jun 88 14:14:37 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA12308; Thu, 9 Jun 88 14:46:03 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8806092046.AA12308@cs.utah.edu>
Date: Thu, 9 Jun 88 14:46:03 MDT
Subject: (another) new version of the non-top-level defining macros proposal
To: cl-compiler@sail.stanford.edu
Item 5 is new, from a suggestion by Walter. I haven't gotten comments from
anyone else on the previous version of this proposal.
-Sandra
Issue: DEFINING-MACROS-NON-TOP-LEVEL
References: CLtL p. 66-70, 143
Issue EVAL-WHEN-NON-TOP-LEVEL
Issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Category: CLARIFICATION, ENHANCEMENT
Edit History: 6-May-88, V1 by Sandra Loosemore
9-Jun-88, V2 by Sandra Loosemore
Problem Description:
CLtL leaves the interpretation of defining forms such as DEFMACRO and
DEFVAR that appear in other than top-level locations unspecified.
Resolution of other issues (EVAL-WHEN-NON-TOP-LEVEL and
COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS) now allows reasonable
semantics to be assigned to defining forms which appear at
non-top-level.
Proposal: DEFINING-MACROS-NON-TOP-LEVEL:ALLOW
(1) Clarify that while defining macros normally appear at top level,
it is meaningful to place them in non-top-level contexts and that the
compiler must handle them properly in all situations. Remove the
language on p. 66 of CLtL which states that the compiler is not
required to recognize defining macros at other than top-level.
(2) The proposal COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
defines a model for specifying how defining macros work. To
summarize, the expansion of the macro (rather than its expander
function) is responsible for storing information about the definition.
Compile-time side effects are typically handled by including one or
more EVAL-WHEN forms in the expansion. A compiler may choose
some other implementation, such as treating defining macros as
implementation-specific special forms, provided that the semantics
are compatible.
(3) Defining macros which define functional objects (such as DEFUN and
DEFMACRO) must ensure that the functions are defined in the lexical
environment in which the defining macro appears. In the model
referred to above, this would normally be implemented by producing a
FUNCTION special form in the macro expansion. For example, the
following code causes the function BAR to be closed over the variable
X:
(let ((x (some-hairy-computation)))
(defun bar (y) (+ x y)))
(4) The language on p. 145 of CLtL, which states that macro functions
are defined in the null lexical environment, should be removed.
Instead, defining forms such as DEFMACRO which make a functional
definition available at the compile time use the environment must
normally appear inside an explicit (EVAL-WHEN (COMPILE) ...) to ensure
that the correct lexical environment is seen.
An example may help clarify why this is necessary. The code fragment
(let ((x (some-hairy-computation)))
(defmacro bar-macro (y) `(+ ,x ,y)))
would macroexpand into something similar to
(let ((x (some-hairy-computation)))
(eval-when (eval compile load)
(setf (macro-function 'bar-macro)
#'(lambda (form env)
(let ((y (second form)))
`(+ ,x ,y))))
'bar-macro))
Since the rules for (EVAL-WHEN (COMPILE) ...) state that evaluation
takes place in the null lexical environment, in this situation X would
be treated as a special variable within the macro function. However,
in the EVAL or LOAD situations, the lexical value of X would be used.
To ensure consistency, the correct definition would be:
(eval-when (eval compile load)
(let ((x (some-hairy-computation)))
(defmacro bar (y) `(+ ,x ,y))))
(5) Clarify that ``top-level forms'' are evaluable data objects read
in from an input source (such as a keyboard or disk file) by
successive calls to the function READ. As a special case, forms
within a top-level PROGN are also considered to be top-level forms.
Specify that top-level forms in a file being compiled are guaranteed
to be processed sequentially, but the order in which subforms of a
top-level form are processed by the compiler is explicitly left
unspecified. It is an error for user code to depend upon the
compile-time side-effects of a defining macro within the same
top-level form in which the defining macro appears.
Rationale:
The notion of a ``top-level form'' is rather confused, since the term
is used in CLtL to refer both to a place where a form may appear (what
this proposal continues to call ``top-level''), and to instances of
forms which traditionally appear there (what this proposal calls
``defining macros'').
There has been a suggestion that the notion of a top-level form should
be extended to include forms in the body of a top-level LET, to allow
forms such as DEFUN to be meaningful there. However, we feel that a
cleaner solution is to remove the restrictions on the placement of
defining macros altogether.
Current Practice:
Cost to implementors:
Cost to users:
None. This is a compatible extension.
Benefits:
The notion of defining macros as being somehow special is removed from
the language. Allowing defining macros to appear anywhere instead of
restricting them to certain positions results in a cleaner language
design.
Discussion:
-------
∂09-Jun-88 1707 CL-Compiler-mailer next order of business
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 9 Jun 88 17:07:34 PDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA17668; Thu, 9 Jun 88 18:06:36 MDT
From: sandra@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8806100006.AA17668@cs.utah.edu>
Date: Thu, 9 Jun 88 18:06:34 MDT
Subject: next order of business
To: cl-compiler@sail.stanford.edu
It seems like issues relating to the treatment of constants in compiled
code, which have been discussed on the common-lisp mailing list for the
past few weeks, should probably be the next thing we try to address. I
believe that the main thing that has to be done here is to explicitly
state that it is an error to destructively modify structured constants
(since the current wording in CLtL allows the compiler to collapse EQUAL
structures), and to clarify exactly what kinds of destructive operations
would be forbidden. For example, I do not believe we would want to
prohibit alteration of the "fields" of a quoted symbol such as the
property list. There are other, more radical approaches we could
take -- such as forbidding implementations to collapse constants or put
them in read-only storage -- but I don't know if any of these would get
much support. Comments, anyone? I could try to sketch out a proposal
on this over the weekend and bring it to Cambridge for discussion.
-Sandra
-------
∂10-Jun-88 0121 CL-Compiler-mailer Compiler Subcommittee meeting and dinner
Received: from ucbarpa.Berkeley.EDU by SAIL.Stanford.EDU with TCP; 10 Jun 88 01:21:25 PDT
Received: by ucbarpa.Berkeley.EDU (5.59/1.28)
id AA21348; Fri, 10 Jun 88 01:20:10 PDT
Received: by franz (3.2/3.14)
id AA04504; Fri, 10 Jun 88 00:59:42 PDT
Received: by feast (5.5/3.14)
id AA00493; Fri, 10 Jun 88 03:50:35 EDT
Date: Fri, 10 Jun 88 03:50:35 EDT
From: franz!feast!smh@ucbarpa.Berkeley.EDU (Steven M. Haflich)
Message-Id: <8806100750.AA00493@feast>
To: franz!sail.stanford.edu!cl-compiler
Subject: Compiler Subcommittee meeting and dinner
There have been a couple positive replies. I propose that people who
want to go to dinner on Tuesday meet at Gigamos at 6PM. We can wait
there until about 6:15, walk to dinner in the neighborhood, and return
to Gigamos around 7:30. We'll try to leave word with the guard where
we go to dinner in case someone is late.
Once again, Gigamos is at Central Square Cambridge, 675 Massachusetts
Avenue, the 7th floor of the "Tofias" building. The security guard
should allow access if you mention Gigamos, but if there is any
problem call 876-6819 and ask for me. I'll try to leave a list of
subcommittee members with the guard.